diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 67445b77..10968e38 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -4,6 +4,10 @@ on: pull_request_target: types: [closed] # fires when PR is closed (merged) +concurrency: + group: backport-${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: contents: write pull-requests: write diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index a33c78e2..65c48051 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,12 +1,13 @@ name: Pre-Commit Checks on: - push: - branches: - - main pull_request: - paths-ignore: - - '**.md' + types: [labeled, opened, synchronize, reopened] + +concurrency: + group: pre-commit-${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: pre-commit: runs-on: ubuntu-22.04 diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml index 815ccb59..5614f893 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -4,6 +4,10 @@ on: pull_request: types: [labeled, opened, synchronize, reopened, closed] +concurrency: + group: pull-requests-release-${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: verify: name: Test Release @@ -12,8 +16,8 @@ jobs: contents: read packages: write + # Run only when the PR carries the "release" label and not closed. if: | - contains(github.event.pull_request.labels.*.name, 'ok-to-test') && contains(github.event.pull_request.labels.*.name, 'release') && github.event.action != 'closed' @@ -72,6 +76,61 @@ jobs: git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }} git push -f origin ${{ steps.get_tag.outputs.tag }} + # Ensure maintenance branch release-X.Y + - name: Ensure maintenance branch release-X.Y + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GH_PAT }} + script: | + const tag = '${{ steps.get_tag.outputs.tag }}'; // e.g. v0.1.3 or v0.1.3-rc3 + const match = tag.match(/^v(\d+)\.(\d+)\.\d+(?:[-\w\.]+)?$/); + if (!match) { + core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-suffix'`); + return; + } + const line = `${match[1]}.${match[2]}`; + const branch = `release-${line}`; + + // Get main branch commit for the tag + const ref = await github.rest.git.getRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${tag}` + }); + + const commitSha = ref.data.object.sha; + + try { + await github.rest.repos.getBranch({ + owner: context.repo.owner, + repo: context.repo.repo, + branch + }); + + await github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `heads/${branch}`, + sha: commitSha, + force: true + }); + console.log(`🔁 Force-updated '${branch}' to ${commitSha}`); + } catch (err) { + if (err.status === 404) { + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/heads/${branch}`, + sha: commitSha + }); + console.log(`✅ Created branch '${branch}' at ${commitSha}`); + } else { + console.error('Unexpected error --', err); + core.setFailed(`Unexpected error creating/updating branch: ${err.message}`); + throw err; + } + } + # Get the latest published release - name: Get the latest published release id: latest_release @@ -102,13 +161,13 @@ jobs: uses: actions/github-script@v7 with: script: | - const tag = '${{ steps.get_tag.outputs.tag }}'; // v0.31.5-rc1 - const m = tag.match(/^v(\d+\.\d+\.\d+)(-rc\d+)?$/); + const tag = '${{ steps.get_tag.outputs.tag }}'; // v0.31.5-rc.1 + const m = tag.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); if (!m) { - core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-rcN'`); + core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); return; } - const version = m[1] + (m[2] ?? ''); // 0.31.5‑rc1 + const version = m[1] + (m[2] ?? ''); // 0.31.5-rc.1 const isRc = Boolean(m[2]); core.setOutput('is_rc', isRc); const outdated = '${{ steps.semver.outputs.comparison-result }}' === '<'; diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index 92226c2a..2f3b3542 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -4,6 +4,10 @@ on: pull_request: types: [labeled, opened, synchronize, reopened] +concurrency: + group: pull-requests-${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: e2e: name: Build and Test @@ -12,20 +16,9 @@ jobs: contents: read packages: write - # ───────────────────────────────────────────────────────────── - # Run automatically for internal PRs (same repo). - # For external PRs (forks) require the "ok‑to‑test" label. # Never run when the PR carries the "release" label. - # ───────────────────────────────────────────────────────────── if: | - !contains(github.event.pull_request.labels.*.name, 'release') && - ( - github.event.pull_request.head.repo.full_name == github.repository || - ( - github.event.pull_request.head.repo.full_name != github.repository && - contains(github.event.pull_request.labels.*.name, 'ok-to-test') - ) - ) + !contains(github.event.pull_request.labels.*.name, 'release') steps: - name: Checkout code diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index f50c9b0a..66376397 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -3,7 +3,14 @@ name: Versioned Tag on: push: tags: - - 'v*.*.*' # vX.Y.Z or vX.Y.Z-rcN + - 'v*.*.*' # vX.Y.Z + - 'v*.*.*-rc.*' # vX.Y.Z-rc.N + - 'v*.*.*-beta.*' # vX.Y.Z-beta.N + - 'v*.*.*-alpha.*' # vX.Y.Z-alpha.N + +concurrency: + group: tags-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: prepare-release: @@ -13,6 +20,7 @@ jobs: contents: write packages: write pull-requests: write + actions: write steps: # Check if a non-draft release with this tag already exists @@ -35,28 +43,28 @@ jobs: if: steps.check_release.outputs.skip == 'true' run: echo "Release already exists, skipping workflow." - # Parse tag meta‑data (rc?, maintenance line, etc.) + # Parse tag meta-data (rc?, maintenance line, etc.) - name: Parse tag if: steps.check_release.outputs.skip == 'false' id: tag uses: actions/github-script@v7 with: script: | - const ref = context.ref.replace('refs/tags/', ''); // e.g. v0.31.5-rc1 - const m = ref.match(/^v(\d+\.\d+\.\d+)(-rc\d+)?$/); + const ref = context.ref.replace('refs/tags/', ''); // e.g. v0.31.5-rc.1 + const m = ref.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); // ['0.31.5', '-rc.1' | '-beta.1' | …] if (!m) { - core.setFailed(`❌ tag '${ref}' must match 'vX.Y.Z' or 'vX.Y.Z-rcN'`); + core.setFailed(`❌ tag '${ref}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); return; } - const version = m[1] + (m[2] ?? ''); // 0.31.5‑rc1 + const version = m[1] + (m[2] ?? ''); // 0.31.5-rc.1 const isRc = Boolean(m[2]); const [maj, min] = m[1].split('.'); - core.setOutput('tag', ref); - core.setOutput('version', version); - core.setOutput('is_rc', isRc); + core.setOutput('tag', ref); // v0.31.5-rc.1 + core.setOutput('version', version); // 0.31.5-rc.1 + core.setOutput('is_rc', isRc); // true core.setOutput('line', `${maj}.${min}`); // 0.31 - # Detect base branch (main or release‑X.Y) the tag was pushed from + # Detect base branch (main or release-X.Y) the tag was pushed from - name: Get base branch if: steps.check_release.outputs.skip == 'false' id: get_base @@ -161,7 +169,7 @@ jobs: }); console.log(`Draft release created for ${tag}`); } else { - console.log(`Re‑using existing release ${tag}`); + console.log(`Re-using existing release ${tag}`); } core.setOutput('upload_url', rel.upload_url); @@ -170,37 +178,11 @@ jobs: if: steps.check_release.outputs.skip == 'false' run: | make assets - make upload_assets VERSION=${{ steps.tag.outputs.version }} + make upload_assets VERSION=${{ steps.tag.outputs.tag }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Ensure long‑lived maintenance branch release‑X.Y - - name: Ensure maintenance branch release‑${{ steps.tag.outputs.line }} - if: | - steps.check_release.outputs.skip == 'false' && - steps.get_base.outputs.branch == 'main' - uses: actions/github-script@v7 - with: - script: | - const branch = `release-${'${{ steps.tag.outputs.line }}'}`; - try { - await github.rest.repos.getBranch({ - owner: context.repo.owner, - repo: context.repo.repo, - branch - }); - console.log(`Branch '${branch}' already exists`); - } catch (_) { - await github.git.createRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `refs/heads/${branch}`, - sha: context.sha - }); - console.log(`Branch '${branch}' created at ${context.sha}`); - } - - # Create release‑X.Y.Z branch and push (force‑update) + # Create release-X.Y.Z branch and push (force-update) - name: Create release branch if: steps.check_release.outputs.skip == 'false' run: | @@ -244,8 +226,3 @@ jobs: } else { console.log(`PR already exists from ${head} to ${base}`); } - - # Run tests - - name: Test - if: steps.check_release.outputs.skip == 'false' - run: make test diff --git a/.gitignore b/.gitignore index 00d89825..de476be5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ _out .git .idea +.vscode # User-specific stuff .idea/**/workspace.xml @@ -75,4 +76,4 @@ fabric.properties .idea/caches/build_file_checksums.ser .DS_Store -**/.DS_Store \ No newline at end of file +**/.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d05ad6f..9f94db8e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: (cd "$dir" && make generate) fi done + git diff --color=always | cat ' language: script files: ^.*$ diff --git a/Makefile b/Makefile index 6ea3ffd5..63f61458 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ build: build-deps make -C packages/system/kubeovn image make -C packages/system/kubeovn-webhook image make -C packages/system/dashboard image + make -C packages/system/metallb image make -C packages/system/kamaji image make -C packages/system/bucket image make -C packages/core/testing image @@ -47,7 +48,6 @@ assets: test: make -C packages/core/testing apply make -C packages/core/testing test - #make -C packages/core/testing test-applications generate: hack/update-codegen.sh diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index f1c10c10..a5624cd3 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -39,6 +39,8 @@ import ( cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" "github.com/cozystack/cozystack/internal/controller" "github.com/cozystack/cozystack/internal/telemetry" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" // +kubebuilder:scaffold:imports ) @@ -51,6 +53,7 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(cozystackiov1alpha1.AddToScheme(scheme)) + utilruntime.Must(helmv2.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -182,6 +185,14 @@ func main() { if err = (&controller.WorkloadReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "WorkloadReconciler") + os.Exit(1) + } + + if err = (&controller.TenantHelmReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Workload") os.Exit(1) diff --git a/docs/changelogs/v0.31.0.md b/docs/changelogs/v0.31.0.md new file mode 100644 index 00000000..2b556e16 --- /dev/null +++ b/docs/changelogs/v0.31.0.md @@ -0,0 +1,97 @@ +This is the third release candidate for the upcoming Cozystack v0.31.0 release. +The release notes show changes accumulated since the release of previous version, Cozystack v0.30.0. + +Cozystack 0.31.0 further advances GPU support, monitoring, and all-around convenience features. + +## New Features and Changes + +* [kubernetes] Introduce GPU support for tenant Kubernetes clusters. (@kvaps in https://github.com/cozystack/cozystack/pull/834) +* Add VerticalPodAutoscaler to a few more components: + * [kubernetes] Kubernetes clusters in user tenants. (@klinch0 in https://github.com/cozystack/cozystack/pull/806) + * [platform] Cozystack dashboard. (@klinch0 in https://github.com/cozystack/cozystack/pull/828) + * [platform] Cozystack etcd-operator (@klinch0 in https://github.com/cozystack/cozystack/pull/850) +* Introduce support for cross-architecture builds and Cozystack on ARM: + * [build] Refactor Makefiles introducing build variables. (@nbykov0 in https://github.com/cozystack/cozystack/pull/907) + * [build] Add support for multi-architecture and cross-platform image builds. (@nbykov0 in https://github.com/cozystack/cozystack/pull/932 and https://github.com/cozystack/cozystack/pull/970) +* [platform] Introduce a new controller to synchronize tenant HelmReleases and propagate configuration changes. (@klinch0 in https://github.com/cozystack/cozystack/pull/870) +* [platform] Introduce options `expose-services`, `expose-ingress` and `expose-external-ips` to the ingress service. (@kvaps in https://github.com/cozystack/cozystack/pull/929) +* [kubevirt] Enable exporting VMs. (@kvaps in https://github.com/cozystack/cozystack/pull/808) +* [kubevirt] Make KubeVirt's CPU allocation ratio configurable. (@lllamnyp in https://github.com/cozystack/cozystack/pull/905) +* [virtual-machine] Add support for various storages. (@kvaps in https://github.com/cozystack/cozystack/pull/974) +* [cozystack-controller] Record the IP address pool and storage class in Workload objects. (@lllamnyp in https://github.com/cozystack/cozystack/pull/831) +* [cilium] Enable Cilium Gateway API. (@zdenekjanda in https://github.com/cozystack/cozystack/pull/924) +* [cilium] Enable user-added parameters in a tenant cluster Cilium. (@lllamnyp in https://github.com/cozystack/cozystack/pull/917) +* [apps] Remove user-facing config of limits and requests. (@lllamnyp in https://github.com/cozystack/cozystack/pull/935) +* Update the Cozystack release policy to include long-lived release branches and start with release candidates. Update CI workflows and docs accordingly. + * Use release branches `release-X.Y` for gathering and releasing fixes after initial `vX.Y.0` release. (@kvaps in https://github.com/cozystack/cozystack/pull/816) + * Automatically create release branches after initial `vX.Y.0` release is published. (@kvaps in https://github.com/cozystack/cozystack/pull/886) + * Introduce Release Candidate versions. Automate patch backporting by applying patches from pull requests labeled `[backport]` to the current release branch. (@kvaps in https://github.com/cozystack/cozystack/pull/841 and https://github.com/cozystack/cozystack/pull/901, @nickvolynkin in https://github.com/cozystack/cozystack/pull/890) + * Support alpha and beta pre-releases. (@kvaps in https://github.com/cozystack/cozystack/pull/978) + * Commit changes in release pipelines under `github-actions `. (@kvaps in https://github.com/cozystack/cozystack/pull/823) + * Describe the Cozystack release workflow. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/817 and https://github.com/cozystack/cozystack/pull/897) + +## Fixes + +* [virtual-machine] Add GPU names to the virtual machine specifications. (@kvaps in https://github.com/cozystack/cozystack/pull/862) +* [virtual-machine] Count Workload resources for pods by requests, not limits. Other improvements to VM resource tracking. (@lllamnyp in https://github.com/cozystack/cozystack/pull/904) +* [platform] Fix installing HelmReleases on initial setup. (@kvaps in https://github.com/cozystack/cozystack/pull/833) +* [platform] Migration scripts update Kubernetes ConfigMap with the current stack version for improved version tracking. (@klinch0 in https://github.com/cozystack/cozystack/pull/840) +* [platform] Reduce requested CPU and RAM for the `kamaji` provider. (@klinch0 in https://github.com/cozystack/cozystack/pull/825) +* [platform] Improve the reconciliation loop for the Cozystack system HelmReleases logic. (@klinch0 in https://github.com/cozystack/cozystack/pull/809 and https://github.com/cozystack/cozystack/pull/810, @kvaps in https://github.com/cozystack/cozystack/pull/811) +* [platform] Remove extra dependencies for the Piraeus operator. (@klinch0 in https://github.com/cozystack/cozystack/pull/856) +* [platform] Refactor dashboard values. (@kvaps in https://github.com/cozystack/cozystack/pull/928, patched by @llamnyp in https://github.com/cozystack/cozystack/pull/952) +* [platform] Make FluxCD artifact disabled by default. (@klinch0 in https://github.com/cozystack/cozystack/pull/964) +* [kubernetes] Update garbage collection of HelmReleases in tenant Kubernetes clusters. (@kvaps in https://github.com/cozystack/cozystack/pull/835) +* [kubernetes] Fix merging `valuesOverride` for tenant clusters. (@kvaps in https://github.com/cozystack/cozystack/pull/879) +* [kubernetes] Fix `ubuntu-container-disk` tag. (@kvaps in https://github.com/cozystack/cozystack/pull/887) +* [kubernetes] Refactor Helm manifests for tenant Kubernetes clusters. (@kvaps in https://github.com/cozystack/cozystack/pull/866) +* [kubernetes] Fix Ingress-NGINX depends on Cert-Manager . (@kvaps in https://github.com/cozystack/cozystack/pull/976) +* [tenant] Fix an issue with accessing external IPs of a cluster from the cluster itself. (@kvaps in https://github.com/cozystack/cozystack/pull/854) +* [cluster-api] Remove the no longer necessary workaround for Kamaji. (@kvaps in https://github.com/cozystack/cozystack/pull/867, patched in https://github.com/cozystack/cozystack/pull/956) +* [monitoring] Remove legacy label "POD" from the exclude filter in metrics. (@xy2 in https://github.com/cozystack/cozystack/pull/826) +* [monitoring] Refactor management etcd monitoring config. Introduce a migration script for updating monitoring resources (`kube-rbac-proxy` daemonset). (@lllamnyp in https://github.com/cozystack/cozystack/pull/799 and https://github.com/cozystack/cozystack/pull/830) +* [monitoring] Fix VerticalPodAutoscaler resource allocation for VMagent. (@klinch0 in https://github.com/cozystack/cozystack/pull/820) +* [postgres] Remove duplicated `template` entry from backup manifest. (@etoshutka in https://github.com/cozystack/cozystack/pull/872) +* [kube-ovn] Fix versions mapping in Makefile. (@kvaps in https://github.com/cozystack/cozystack/pull/883) +* [dx] Automatically detect version for migrations in the installer.sh. (@kvaps in https://github.com/cozystack/cozystack/pull/837) +* [e2e] Increase timeout durations for `capi` and `keycloak` to improve reliability during environment setup. (@kvaps in https://github.com/cozystack/cozystack/pull/858) +* [e2e] Fix `device_ownership_from_security_context` CRI. (@dtrdnk in https://github.com/cozystack/cozystack/pull/896) +* [e2e] Return `genisoimage` to the e2e-test Dockerfile (@gwynbleidd2106 in https://github.com/cozystack/cozystack/pull/962) +* [ci] Improve the check for `versions_map` running on pull requests. (@kvaps and @klinch0 in https://github.com/cozystack/cozystack/pull/836, https://github.com/cozystack/cozystack/pull/842, and https://github.com/cozystack/cozystack/pull/845) +* [ci] If the release step was skipped on a tag, skip tests as well. (@kvaps in https://github.com/cozystack/cozystack/pull/822) +* [ci] Allow CI to cancel the previous job if a new one is scheduled. (@kvaps in https://github.com/cozystack/cozystack/pull/873) +* [ci] Use the correct version name when uploading build assets to the release page. (@kvaps in https://github.com/cozystack/cozystack/pull/876) +* [ci] Stop using `ok-to-test` label to trigger CI in pull requests. (@kvaps in https://github.com/cozystack/cozystack/pull/875) +* [ci] Do not run tests in the release building pipeline. (@kvaps in https://github.com/cozystack/cozystack/pull/882) +* [ci] Fix release branch creation. (@kvaps in https://github.com/cozystack/cozystack/pull/884) +* [ci, dx] Reduce noise in the test logs by suppressing the `wget` progress bar. (@lllamnyp in https://github.com/cozystack/cozystack/pull/865) +* [ci] Revert "automatically trigger tests in releasing PR". (@kvaps in https://github.com/cozystack/cozystack/pull/900) +* [ci] Force-update release branch on tagged main commits . (@kvaps in https://github.com/cozystack/cozystack/pull/977) +* [docs] Explain that tenants cannot have dashes in the names. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/980) + +## Dependencies + +* MetalLB s now included directly as a patched image based on version 0.14.9. (@lllamnyp in https://github.com/cozystack/cozystack/pull/945) +* Update Kubernetes to v1.32.4. (@kvaps in https://github.com/cozystack/cozystack/pull/949) +* Update Talos Linux to v1.10.1. (@kvaps in https://github.com/cozystack/cozystack/pull/931) +* Update Cilium to v1.17.3. (@kvaps in https://github.com/cozystack/cozystack/pull/848) +* Update LINSTOR to v1.31.0. (@kvaps in https://github.com/cozystack/cozystack/pull/846) +* Update Kube-OVN to v1.13.11. (@kvaps in https://github.com/cozystack/cozystack/pull/847, @lllamnyp in https://github.com/cozystack/cozystack/pull/922) +* Update tenant Kubernetes to v1.32. (@kvaps in https://github.com/cozystack/cozystack/pull/871) +* Update flux-operator to 0.20.0. (@kingdonb in https://github.com/cozystack/cozystack/pull/880 and https://github.com/cozystack/cozystack/pull/934) +* Update multiple Cluster API components. (@kvaps in https://github.com/cozystack/cozystack/pull/867 and https://github.com/cozystack/cozystack/pull/947) +* Update KamajiControlPlane to edge-25.4.1. (@kvaps in https://github.com/cozystack/cozystack/pull/953, fixed by @nbykov0 in https://github.com/cozystack/cozystack/pull/983) +* Update cert-manager to v1.17.2. (@kvaps in https://github.com/cozystack/cozystack/pull/975) + +## Maintenance + +* Add @klinch0 to CODEOWNERS. (@kvaps in https://github.com/cozystack/cozystack/pull/838) + +## New Contributors + +* @etoshutka made their first contribution in https://github.com/cozystack/cozystack/pull/872 +* @dtrdnk made their first contribution in https://github.com/cozystack/cozystack/pull/896 +* @zdenekjanda made their first contribution in https://github.com/cozystack/cozystack/pull/924 +* @gwynbleidd2106 made their first contribution in https://github.com/cozystack/cozystack/pull/962 + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.30.0...v0.31.0-rc.3 diff --git a/docs/release.md b/docs/release.md index 062b7a56..22366f6b 100644 --- a/docs/release.md +++ b/docs/release.md @@ -1,10 +1,37 @@ # Release Workflow -This section explains how Cozystack builds and releases are made. +This document describes Cozystack’s release process. + +## Introduction + +Cozystack uses a staged release process to ensure stability and flexibility during development. + +There are three types of releases: + +- **Release Candidates (RC)** – Preview versions (e.g., `v0.42.0-rc.1`) used for final testing and validation. +- **Regular Releases** – Final versions (e.g., `v0.42.0`) that are feature-complete and thoroughly tested. +- **Patch Releases** – Bugfix-only updates (e.g., `v0.42.1`) made after a stable release, based on a dedicated release branch. + +Each type plays a distinct role in delivering reliable and tested updates while allowing ongoing development to continue smoothly. + +## Release Candidates + +Release candidates are Cozystack versions that introduce new features and are published before a stable release. +Their purpose is to help validate stability before finalizing a new feature release. +They allow for final rounds of testing and bug fixes without freezing development. + +Release candidates are given numbers `vX.Y.0-rc.N`, for example, `v0.42.0-rc.1`. +They are created directly in the `main` branch. +An RC is typically tagged when all major features for the upcoming release have been merged into main and the release enters its testing phase. +However, new features and changes can still be added before the regular release `vX.Y.0`. + +Each RC contributes to a cumulative set of release notes that will be finalized when `vX.Y.0` is released. +After testing, if no critical issues remain, the regular release (`vX.Y.0`) is tagged from the last RC or a later commit in main. +This begins the regular release process, creates a dedicated `release-X.Y` branch, and opens the way for patch releases. ## Regular Releases -When making regular releases, we take a commit in `main` and decide to make it a release `x.y.0`. +When making a regular release, we tag the latest RC or a subsequent minimal-change commit as `vX.Y.0`. In this explanation, we'll use version `v0.42.0` as an example: ```mermaid diff --git a/hack/cozytest.sh b/hack/cozytest.sh new file mode 100755 index 00000000..acf0db35 --- /dev/null +++ b/hack/cozytest.sh @@ -0,0 +1,117 @@ +#!/bin/sh +############################################################################### +# cozytest.sh - Bats-compatible test runner with live trace and enhanced # +# output, written in pure shell # +############################################################################### +set -eu + +TEST_FILE=${1:?Usage: ./cozytest.sh [pattern]} +PATTERN=${2:-*} +LINE='----------------------------------------------------------------' + +cols() { stty size 2>/dev/null | awk '{print $2}' || echo 80; } +MAXW=$(( $(cols) - 12 )); [ "$MAXW" -lt 40 ] && MAXW=70 +BEGIN=$(date +%s) +timestamp() { s=$(( $(date +%s) - BEGIN )); printf '[%02d:%02d]' $((s/60)) $((s%60)); } + +############################################################################### +# run_one # +############################################################################### +run_one() { + fn=$1 title=$2 + tmp=$(mktemp -d) || { echo "Failed to create temp directory" >&2; exit 1; } + log="$tmp/log" + + echo "╭ » Run test: $title" + START=$(date +%s) + skip_next="+ $fn" # первую строку трассировки с именем функции пропустим + + { + ( + PS4='+ ' # prefix for set -x + set -eu -x # strict + trace + "$fn" + ) + printf '__RC__%s\n' "$?" + } 2>&1 | tee "$log" | while IFS= read -r line; do + case "$line" in + '__RC__'*) : ;; + '+ '*) cmd=${line#'+ '} + [ "$cmd" = "${skip_next#+ }" ] && continue + case "$cmd" in + 'set -e'|'set -x'|'set -u'|'return 0') continue ;; + esac + out=$cmd ;; + *) out=$line ;; + esac + now=$(( $(date +%s) - START )) + [ ${#out} -gt "$MAXW" ] && out="$(printf '%.*s…' "$MAXW" "$out")" + printf '┊[%02d:%02d] %s\n' $((now/60)) $((now%60)) "$out" + done + + rc=$(awk '/^__RC__/ {print substr($0,7)}' "$log" | tail -n1) + [ -z "$rc" ] && rc=1 + now=$(( $(date +%s) - START )) + + if [ "$rc" -eq 0 ]; then + printf '╰[%02d:%02d] ✅ Test OK: %s\n' $((now/60)) $((now%60)) "$title" + else + printf '╰[%02d:%02d] ❌ Test failed: %s (exit %s)\n' \ + $((now/60)) $((now%60)) "$title" "$rc" + echo "----- captured output -----------------------------------------" + grep -v '^__RC__' "$log" + echo "$LINE" + exit "$rc" + fi + + rm -rf "$tmp" +} + +############################################################################### +# convert .bats -> shell-functions # +############################################################################### +TMP_SH=$(mktemp) || { echo "Failed to create temp file" >&2; exit 1; } +trap 'rm -f "$TMP_SH"' EXIT +awk ' + /^@test[[:space:]]+"/ { + line = substr($0, index($0, "\"") + 1) + title = substr(line, 1, index(line, "\"") - 1) + fname = "test_" + for (i = 1; i <= length(title); i++) { + c = substr(title, i, 1) + fname = fname (c ~ /[A-Za-z0-9]/ ? c : "_") + } + printf("### %s\n", title) + printf("%s() {\n", fname) + print " set -e" # ошибка → падение теста + next + } + /^}$/ { + print " return 0" # если автор не сделал exit 1 — тест ОК + print "}" + next + } + { print } +' "$TEST_FILE" > "$TMP_SH" + +[ -f "$TMP_SH" ] || { echo "Failed to generate test functions" >&2; exit 1; } +# shellcheck disable=SC1090 +. "$TMP_SH" + +############################################################################### +# run selected tests # +############################################################################### +awk -v pat="$PATTERN" ' + /^### / { + title = substr($0, 5) + name = "test_" + for (i = 1; i <= length(title); i++) { + c = substr(title, i, 1) + name = name (c ~ /[A-Za-z0-9]/ ? c : "_") + } + if (pat == "*" || index(title, pat) > 0) + printf("%s %s\n", name, title) + } +' "$TMP_SH" | while IFS=' ' read -r fn title; do + run_one "$fn" "$title" +done diff --git a/hack/e2e-apps.bats b/hack/e2e-apps.bats new file mode 100755 index 00000000..9610a64a --- /dev/null +++ b/hack/e2e-apps.bats @@ -0,0 +1,94 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------------------- +# Cozystack end‑to‑end provisioning test (Bats) +# ----------------------------------------------------------------------------- + +@test "Create tenant with isolated mode enabled" { + kubectl create -f - <<EOF +apiVersion: apps.cozystack.io/v1alpha1 +kind: Tenant +metadata: + name: test + namespace: tenant-root +spec: + etcd: false + host: "" + ingress: false + isolated: true + monitoring: false + resourceQuotas: {} + seaweedfs: false +EOF + kubectl wait hr/tenant-test -n tenant-root --timeout=1m --for=condition=ready + kubectl wait namespace tenant-test --timeout=20s --for=jsonpath='{.status.phase}'=Active +} + +@test "Create a tenant Kubernetes control plane" { + kubectl create -f - <<EOF +apiVersion: apps.cozystack.io/v1alpha1 +kind: Kubernetes +metadata: + name: test + namespace: tenant-test +spec: + addons: + certManager: + enabled: false + valuesOverride: {} + cilium: + valuesOverride: {} + fluxcd: + enabled: false + valuesOverride: {} + gatewayAPI: + enabled: false + gpuOperator: + enabled: false + valuesOverride: {} + ingressNginx: + enabled: true + hosts: [] + valuesOverride: {} + monitoringAgents: + enabled: false + valuesOverride: {} + verticalPodAutoscaler: + valuesOverride: {} + controlPlane: + apiServer: + resources: {} + resourcesPreset: small + controllerManager: + resources: {} + resourcesPreset: micro + konnectivity: + server: + resources: {} + resourcesPreset: micro + replicas: 2 + scheduler: + resources: {} + resourcesPreset: micro + host: "" + nodeGroups: + md0: + ephemeralStorage: 20Gi + gpus: [] + instanceType: u1.medium + maxReplicas: 10 + minReplicas: 0 + resources: + cpu: "" + memory: "" + roles: + - ingress-nginx + storageClass: replicated +EOF + kubectl wait namespace tenant-test --timeout=20s --for=jsonpath='{.status.phase}'=Active + timeout 10 sh -ec 'until kubectl get kamajicontrolplane -n tenant-test kubernetes-test; do sleep 1; done' + kubectl wait --for=condition=TenantControlPlaneCreated kamajicontrolplane -n tenant-test kubernetes-test --timeout=4m + kubectl wait tcp -n tenant-test kubernetes-test --timeout=2m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready + kubectl wait deploy --timeout=4m --for=condition=available -n tenant-test kubernetes-test kubernetes-test-cluster-autoscaler kubernetes-test-kccm kubernetes-test-kcsi-controller + kubectl wait machinedeployment kubernetes-test-md0 -n tenant-test --timeout=1m --for=jsonpath='{.status.replicas}'=2 + kubectl wait machinedeployment kubernetes-test-md0 -n tenant-test --timeout=5m --for=jsonpath='{.status.v1beta2.readyReplicas}'=2 +} diff --git a/hack/e2e-cluster.bats b/hack/e2e-cluster.bats new file mode 100755 index 00000000..39e2aff4 --- /dev/null +++ b/hack/e2e-cluster.bats @@ -0,0 +1,387 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------------------- +# Cozystack end‑to‑end provisioning test (Bats) +# ----------------------------------------------------------------------------- + +@test "Environment variable COZYSTACK_INSTALLER_YAML is defined" { + if [ -z "${COZYSTACK_INSTALLER_YAML:-}" ]; then + echo 'COZYSTACK_INSTALLER_YAML environment variable is not set!' >&2 + echo >&2 + echo 'Please export it with the following command:' >&2 + echo ' export COZYSTACK_INSTALLER_YAML=$(helm template -n cozy-system installer packages/core/installer)' >&2 + exit 1 + fi +} + +@test "IPv4 forwarding is enabled" { + if [ "$(cat /proc/sys/net/ipv4/ip_forward)" != 1 ]; then + echo "IPv4 forwarding is disabled!" >&2 + echo >&2 + echo "Enable it with:" >&2 + echo " echo 1 > /proc/sys/net/ipv4/ip_forward" >&2 + exit 1 + fi +} + +@test "Clean previous VMs" { + kill $(cat srv1/qemu.pid srv2/qemu.pid srv3/qemu.pid 2>/dev/null) 2>/dev/null || true + rm -rf srv1 srv2 srv3 +} + +@test "Prepare networking and masquerading" { + ip link del cozy-br0 2>/dev/null || true + ip link add cozy-br0 type bridge + ip link set cozy-br0 up + ip address add 192.168.123.1/24 dev cozy-br0 + + # Masquerading rule – idempotent (delete first, then add) + iptables -t nat -D POSTROUTING -s 192.168.123.0/24 ! -d 192.168.123.0/24 -j MASQUERADE 2>/dev/null || true + iptables -t nat -A POSTROUTING -s 192.168.123.0/24 ! -d 192.168.123.0/24 -j MASQUERADE +} + +@test "Prepare cloud‑init drive for VMs" { + mkdir -p srv1 srv2 srv3 + + # Generate cloud‑init ISOs + for i in 1 2 3; do + echo "hostname: srv${i}" > "srv${i}/meta-data" + + cat > "srv${i}/user-data" <<'EOF' +#cloud-config +EOF + + cat > "srv${i}/network-config" <<EOF +version: 2 +ethernets: + eth0: + dhcp4: false + addresses: + - "192.168.123.1${i}/26" + gateway4: "192.168.123.1" + nameservers: + search: [cluster.local] + addresses: [8.8.8.8] +EOF + + ( cd "srv${i}" && genisoimage \ + -output seed.img \ + -volid cidata -rational-rock -joliet \ + user-data meta-data network-config ) + done +} + +@test "Download Talos NoCloud image" { + if [ ! -f nocloud-amd64.raw ]; then + wget https://github.com/cozystack/cozystack/releases/latest/download/nocloud-amd64.raw.xz \ + -O nocloud-amd64.raw.xz --show-progress --output-file /dev/stdout --progress=dot:giga 2>/dev/null + rm -f nocloud-amd64.raw + xz --decompress nocloud-amd64.raw.xz + fi +} + +@test "Prepare VM disks" { + for i in 1 2 3; do + cp nocloud-amd64.raw srv${i}/system.img + qemu-img resize srv${i}/system.img 20G + qemu-img create srv${i}/data.img 100G + done +} + +@test "Create tap devices" { + for i in 1 2 3; do + ip link del cozy-srv${i} 2>/dev/null || true + ip tuntap add dev cozy-srv${i} mode tap + ip link set cozy-srv${i} up + ip link set cozy-srv${i} master cozy-br0 + done +} + +@test "Boot QEMU VMs" { + for i in 1 2 3; do + qemu-system-x86_64 -machine type=pc,accel=kvm -cpu host -smp 8 -m 16384 \ + -device virtio-net,netdev=net0,mac=52:54:00:12:34:5${i} \ + -netdev tap,id=net0,ifname=cozy-srv${i},script=no,downscript=no \ + -drive file=srv${i}/system.img,if=virtio,format=raw \ + -drive file=srv${i}/seed.img,if=virtio,format=raw \ + -drive file=srv${i}/data.img,if=virtio,format=raw \ + -display none -daemonize -pidfile srv${i}/qemu.pid + done + + # Give qemu a few seconds to start up networking + sleep 5 +} + +@test "Wait until Talos API port 50000 is reachable on all machines" { + timeout 60 sh -ec 'until nc -nz 192.168.123.11 50000 && nc -nz 192.168.123.12 50000 && nc -nz 192.168.123.13 50000; do sleep 1; done' +} + +@test "Generate Talos cluster configuration" { + # Cluster‑wide patches + cat > patch.yaml <<'EOF' +machine: + kubelet: + nodeIP: + validSubnets: + - 192.168.123.0/24 + extraConfig: + maxPods: 512 + kernel: + modules: + - name: openvswitch + - name: drbd + parameters: + - usermode_helper=disabled + - name: zfs + - name: spl + registries: + mirrors: + docker.io: + endpoints: + - https://mirror.gcr.io + files: + - content: | + [plugins] + [plugins."io.containerd.cri.v1.runtime"] + device_ownership_from_security_context = true + path: /etc/cri/conf.d/20-customization.part + op: create + +cluster: + apiServer: + extraArgs: + oidc-issuer-url: "https://keycloak.example.org/realms/cozy" + oidc-client-id: "kubernetes" + oidc-username-claim: "preferred_username" + oidc-groups-claim: "groups" + network: + cni: + name: none + dnsDomain: cozy.local + podSubnets: + - 10.244.0.0/16 + serviceSubnets: + - 10.96.0.0/16 +EOF + + # Control‑plane‑only patches + cat > patch-controlplane.yaml <<'EOF' +machine: + nodeLabels: + node.kubernetes.io/exclude-from-external-load-balancers: + $patch: delete + network: + interfaces: + - interface: eth0 + vip: + ip: 192.168.123.10 +cluster: + allowSchedulingOnControlPlanes: true + controllerManager: + extraArgs: + bind-address: 0.0.0.0 + scheduler: + extraArgs: + bind-address: 0.0.0.0 + apiServer: + certSANs: + - 127.0.0.1 + proxy: + disabled: true + discovery: + enabled: false + etcd: + advertisedSubnets: + - 192.168.123.0/24 +EOF + + # Generate secrets once + if [ ! -f secrets.yaml ]; then + talosctl gen secrets + fi + + rm -f controlplane.yaml worker.yaml talosconfig kubeconfig + talosctl gen config --with-secrets secrets.yaml cozystack https://192.168.123.10:6443 \ + --config-patch=@patch.yaml --config-patch-control-plane @patch-controlplane.yaml +} + +@test "Apply Talos configuration to the node" { + # Apply the configuration to all three nodes + for node in 11 12 13; do + talosctl apply -f controlplane.yaml -n 192.168.123.${node} -e 192.168.123.${node} -i + done + + # Wait for Talos services to come up again + timeout 60 sh -ec 'until nc -nz 192.168.123.11 50000 && nc -nz 192.168.123.12 50000 && nc -nz 192.168.123.13 50000; do sleep 1; done' +} + +@test "Bootstrap Talos cluster" { + # Bootstrap etcd on the first node + timeout 10 sh -ec 'until talosctl bootstrap -n 192.168.123.11 -e 192.168.123.11; do sleep 1; done' + + # Wait until etcd is healthy + timeout 180 sh -ec 'until talosctl etcd members -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 >/dev/null 2>&1; do sleep 1; done' + timeout 60 sh -ec 'while talosctl etcd members -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 2>&1 | grep -q "rpc error"; do sleep 1; done' + + # Retrieve kubeconfig + rm -f kubeconfig + talosctl kubeconfig kubeconfig -e 192.168.123.10 -n 192.168.123.10 + + # Wait until all three nodes register in Kubernetes + timeout 60 sh -ec 'until [ $(kubectl get node --no-headers | wc -l) -eq 3 ]; do sleep 1; done' +} + +@test "Install Cozystack" { + # Create namespace & configmap required by installer + kubectl create namespace cozy-system --dry-run=client -o yaml | kubectl apply -f - + kubectl create configmap cozystack -n cozy-system \ + --from-literal=bundle-name=paas-full \ + --from-literal=ipv4-pod-cidr=10.244.0.0/16 \ + --from-literal=ipv4-pod-gateway=10.244.0.1 \ + --from-literal=ipv4-svc-cidr=10.96.0.0/16 \ + --from-literal=ipv4-join-cidr=100.64.0.0/16 \ + --from-literal=root-host=example.org \ + --from-literal=api-server-endpoint=https://192.168.123.10:6443 \ + --dry-run=client -o yaml | kubectl apply -f - + + # Apply installer manifests from env variable + echo "$COZYSTACK_INSTALLER_YAML" | kubectl apply -f - + + # Wait for the installer deployment to become available + kubectl wait deployment/cozystack -n cozy-system --timeout=1m --for=condition=Available + + # Wait until HelmReleases appear & reconcile them + timeout 60 sh -ec 'until kubectl get hr -A | grep -q cozys; do sleep 1; done' + sleep 5 + kubectl get hr -A | awk 'NR>1 {print "kubectl wait --timeout=15m --for=condition=ready -n "$1" hr/"$2" &"} END {print "wait"}' | sh -ex + + # Fail the test if any HelmRelease is not Ready + if kubectl get hr -A | grep -v " True " | grep -v NAME; then + kubectl get hr -A + fail "Some HelmReleases failed to reconcile" + fi +} + +@test "Wait for Cluster‑API provider deployments" { + # Wait for Cluster‑API provider deployments + timeout 60 sh -ec 'until kubectl get deploy -n cozy-cluster-api capi-controller-manager capi-kamaji-controller-manager capi-kubeadm-bootstrap-controller-manager capi-operator-cluster-api-operator capk-controller-manager >/dev/null 2>&1; do sleep 1; done' + kubectl wait deployment/capi-controller-manager deployment/capi-kamaji-controller-manager deployment/capi-kubeadm-bootstrap-controller-manager deployment/capi-operator-cluster-api-operator deployment/capk-controller-manager -n cozy-cluster-api --timeout=1m --for=condition=available +} + +@test "Wait for LINSTOR and configure storage" { + # Linstor controller and nodes + kubectl wait deployment/linstor-controller -n cozy-linstor --timeout=5m --for=condition=available + timeout 60 sh -ec 'until [ $(kubectl exec -n cozy-linstor deploy/linstor-controller -- linstor node list | grep -c Online) -eq 3 ]; do sleep 1; done' + + for node in srv1 srv2 srv3; do + kubectl exec -n cozy-linstor deploy/linstor-controller -- linstor ps cdp zfs ${node} /dev/vdc --pool-name data --storage-pool data + done + + # Storage classes + kubectl apply -f - <<'EOF' +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: local + annotations: + storageclass.kubernetes.io/is-default-class: "true" +provisioner: linstor.csi.linbit.com +parameters: + linstor.csi.linbit.com/storagePool: "data" + linstor.csi.linbit.com/layerList: "storage" + linstor.csi.linbit.com/allowRemoteVolumeAccess: "false" +volumeBindingMode: WaitForFirstConsumer +allowVolumeExpansion: true +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: replicated +provisioner: linstor.csi.linbit.com +parameters: + linstor.csi.linbit.com/storagePool: "data" + linstor.csi.linbit.com/autoPlace: "3" + linstor.csi.linbit.com/layerList: "drbd storage" + linstor.csi.linbit.com/allowRemoteVolumeAccess: "true" + property.linstor.csi.linbit.com/DrbdOptions/auto-quorum: suspend-io + property.linstor.csi.linbit.com/DrbdOptions/Resource/on-no-data-accessible: suspend-io + property.linstor.csi.linbit.com/DrbdOptions/Resource/on-suspended-primary-outdated: force-secondary + property.linstor.csi.linbit.com/DrbdOptions/Net/rr-conflict: retry-connect +volumeBindingMode: WaitForFirstConsumer +allowVolumeExpansion: true +EOF +} + +@test "Wait for MetalLB and configure address pool" { + # MetalLB address pool + kubectl apply -f - <<'EOF' +--- +apiVersion: metallb.io/v1beta1 +kind: L2Advertisement +metadata: + name: cozystack + namespace: cozy-metallb +spec: + ipAddressPools: [cozystack] +--- +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: cozystack + namespace: cozy-metallb +spec: + addresses: [192.168.123.200-192.168.123.250] + autoAssign: true + avoidBuggyIPs: false +EOF +} + +@test "Check Cozystack API service" { + kubectl wait --for=condition=Available apiservices/v1alpha1.apps.cozystack.io --timeout=2m +} + +@test "Configure Tenant and wait for applications" { + # Patch root tenant and wait for its releases + kubectl patch tenants/root -n tenant-root --type merge -p '{"spec":{"host":"example.org","ingress":true,"monitoring":true,"etcd":true,"isolated":true}}' + + timeout 60 sh -ec 'until kubectl get hr -n tenant-root etcd ingress monitoring tenant-root >/dev/null 2>&1; do sleep 1; done' + kubectl wait hr/etcd hr/ingress hr/tenant-root -n tenant-root --timeout=2m --for=condition=ready + + if ! kubectl wait hr/monitoring -n tenant-root --timeout=2m --for=condition=ready; then + flux reconcile hr monitoring -n tenant-root --force + kubectl wait hr/monitoring -n tenant-root --timeout=2m --for=condition=ready + fi + + # Expose Cozystack services through ingress + kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"expose-services":"api,dashboard,cdi-uploadproxy,vm-exportproxy,keycloak"}}' + + # NGINX ingress controller + timeout 60 sh -ec 'until kubectl get deploy root-ingress-controller -n tenant-root >/dev/null 2>&1; do sleep 1; done' + kubectl wait deploy/root-ingress-controller -n tenant-root --timeout=5m --for=condition=available + + # etcd statefulset + kubectl wait sts/etcd -n tenant-root --for=jsonpath='{.status.readyReplicas}'=3 --timeout=5m + + # VictoriaMetrics components + kubectl wait vmalert/vmalert-shortterm vmalertmanager/alertmanager -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m + kubectl wait vlogs/generic -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m + kubectl wait vmcluster/shortterm vmcluster/longterm -n tenant-root --for=jsonpath='{.status.clusterStatus}'=operational --timeout=5m + + # Grafana + kubectl wait clusters.postgresql.cnpg.io/grafana-db -n tenant-root --for=condition=ready --timeout=5m + kubectl wait deploy/grafana-deployment -n tenant-root --for=condition=available --timeout=5m + + # Verify Grafana via ingress + ingress_ip=$(kubectl get svc root-ingress-controller -n tenant-root -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + if ! curl -sS -k "https://${ingress_ip}" -H 'Host: grafana.example.org' --max-time 30 | grep -q Found; then + echo "Failed to access Grafana via ingress at ${ingress_ip}" >&2 + exit 1 + fi +} + +@test "Keycloak OIDC stack is healthy" { + kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"oidc-enabled":"true"}}' + + timeout 120 sh -ec 'until kubectl get hr -n cozy-keycloak keycloak keycloak-configure keycloak-operator >/dev/null 2>&1; do sleep 1; done' + kubectl wait hr/keycloak hr/keycloak-configure hr/keycloak-operator -n cozy-keycloak --timeout=10m --for=condition=ready +} diff --git a/hack/e2e.application.sh b/hack/e2e.application.sh deleted file mode 100755 index 792630de..00000000 --- a/hack/e2e.application.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/bin/bash - -RED='\033[0;31m' -GREEN='\033[0;32m' -RESET='\033[0m' -YELLOW='\033[0;33m' - - -ROOT_NS="tenant-root" -TEST_TENANT="tenant-e2e" - -values_base_path="/hack/testdata/" -checks_base_path="/hack/testdata/" - -function delete_hr() { - local release_name="$1" - local namespace="$2" - - if [[ -z "$release_name" ]]; then - echo -e "${RED}Error: Release name is required.${RESET}" - exit 1 - fi - - if [[ -z "$namespace" ]]; then - echo -e "${RED}Error: Namespace name is required.${RESET}" - exit 1 - fi - - if [[ "$release_name" == "tenant-e2e" ]]; then - echo -e "${YELLOW}Skipping deletion for release tenant-e2e.${RESET}" - return 0 - fi - - kubectl delete helmrelease $release_name -n $namespace -} - -function install_helmrelease() { - local release_name="$1" - local namespace="$2" - local chart_path="$3" - local repo_name="$4" - local repo_ns="$5" - local values_file="$6" - - if [[ -z "$release_name" ]]; then - echo -e "${RED}Error: Release name is required.${RESET}" - exit 1 - fi - - if [[ -z "$namespace" ]]; then - echo -e "${RED}Error: Namespace name is required.${RESET}" - exit 1 - fi - - if [[ -z "$chart_path" ]]; then - echo -e "${RED}Error: Chart path name is required.${RESET}" - exit 1 - fi - - if [[ -n "$values_file" && -f "$values_file" ]]; then - local values_section - values_section=$(echo " values:" && sed 's/^/ /' "$values_file") - fi - - local helmrelease_file=$(mktemp /tmp/HelmRelease.XXXXXX.yaml) - { - echo "apiVersion: helm.toolkit.fluxcd.io/v2" - echo "kind: HelmRelease" - echo "metadata:" - echo " labels:" - echo " cozystack.io/ui: \"true\"" - echo " name: \"$release_name\"" - echo " namespace: \"$namespace\"" - echo "spec:" - echo " chart:" - echo " spec:" - echo " chart: \"$chart_path\"" - echo " reconcileStrategy: Revision" - echo " sourceRef:" - echo " kind: HelmRepository" - echo " name: \"$repo_name\"" - echo " namespace: \"$repo_ns\"" - echo " version: '*'" - echo " interval: 1m0s" - echo " timeout: 5m0s" - [[ -n "$values_section" ]] && echo "$values_section" - } > "$helmrelease_file" - - kubectl apply -f "$helmrelease_file" - - rm -f "$helmrelease_file" -} - -function install_tenant (){ - local release_name="$1" - local namespace="$2" - local values_file="${values_base_path}tenant/values.yaml" - local repo_name="cozystack-apps" - local repo_ns="cozy-public" - install_helmrelease "$release_name" "$namespace" "tenant" "$repo_name" "$repo_ns" "$values_file" -} - -function make_extra_checks(){ - local checks_file="$1" - echo "after exec make $checks_file" - if [[ -n "$checks_file" && -f "$checks_file" ]]; then - echo -e "${YELLOW}Start extra checks with file: ${checks_file}${RESET}" - - fi -} - -function check_helmrelease_status() { - local release_name="$1" - local namespace="$2" - local checks_file="$3" - local timeout=300 # Timeout in seconds - local interval=5 # Interval between checks in seconds - local elapsed=0 - - - while [[ $elapsed -lt $timeout ]]; do - local status_output - status_output=$(kubectl get helmrelease "$release_name" -n "$namespace" -o json | jq -r '.status.conditions[-1].reason') - - if [[ "$status_output" == "InstallSucceeded" || "$status_output" == "UpgradeSucceeded" ]]; then - echo -e "${GREEN}Helm release '$release_name' is ready.${RESET}" - make_extra_checks "$checks_file" - delete_hr $release_name $namespace - return 0 - elif [[ "$status_output" == "InstallFailed" ]]; then - echo -e "${RED}Helm release '$release_name': InstallFailed${RESET}" - exit 1 - else - echo -e "${YELLOW}Helm release '$release_name' is not ready. Current status: $status_output${RESET}" - fi - - sleep "$interval" - elapsed=$((elapsed + interval)) - done - - echo -e "${RED}Timeout reached. Helm release '$release_name' is still not ready after $timeout seconds.${RESET}" - exit 1 -} - -chart_name="$1" - -if [ -z "$chart_name" ]; then - echo -e "${RED}No chart name provided. Exiting...${RESET}" - exit 1 -fi - - -checks_file="${checks_base_path}${chart_name}/check.sh" -repo_name="cozystack-apps" -repo_ns="cozy-public" -release_name="$chart_name-e2e" -values_file="${values_base_path}${chart_name}/values.yaml" - -install_tenant $TEST_TENANT $ROOT_NS -check_helmrelease_status $TEST_TENANT $ROOT_NS "${checks_base_path}tenant/check.sh" - -echo -e "${YELLOW}Running tests for chart: $chart_name${RESET}" - -install_helmrelease $release_name $TEST_TENANT $chart_name $repo_name $repo_ns $values_file -check_helmrelease_status $release_name $TEST_TENANT $checks_file diff --git a/hack/e2e.sh b/hack/e2e.sh deleted file mode 100755 index 9857a042..00000000 --- a/hack/e2e.sh +++ /dev/null @@ -1,361 +0,0 @@ -#!/bin/bash -if [ "$COZYSTACK_INSTALLER_YAML" = "" ]; then - echo 'COZYSTACK_INSTALLER_YAML variable is not set!' >&2 - echo 'please set it with following command:' >&2 - echo >&2 - echo 'export COZYSTACK_INSTALLER_YAML=$(helm template -n cozy-system installer packages/core/installer)' >&2 - echo >&2 - exit 1 -fi - -if [ "$(cat /proc/sys/net/ipv4/ip_forward)" != 1 ]; then - echo "IPv4 forwarding is not enabled!" >&2 - echo 'please enable forwarding with the following command:' >&2 - echo >&2 - echo 'echo 1 > /proc/sys/net/ipv4/ip_forward' >&2 - echo >&2 - exit 1 -fi - -set -x -set -e - -kill `cat srv1/qemu.pid srv2/qemu.pid srv3/qemu.pid` || true - -ip link del cozy-br0 || true -ip link add cozy-br0 type bridge -ip link set cozy-br0 up -ip addr add 192.168.123.1/24 dev cozy-br0 - -# Enable masquerading -iptables -t nat -D POSTROUTING -s 192.168.123.0/24 ! -d 192.168.123.0/24 -j MASQUERADE 2>/dev/null || true -iptables -t nat -A POSTROUTING -s 192.168.123.0/24 ! -d 192.168.123.0/24 -j MASQUERADE - -rm -rf srv1 srv2 srv3 -mkdir -p srv1 srv2 srv3 - -# Prepare cloud-init -for i in 1 2 3; do - echo "hostname: srv$i" > "srv$i/meta-data" - echo '#cloud-config' > "srv$i/user-data" - cat > "srv$i/network-config" <<EOT -version: 2 -ethernets: - eth0: - dhcp4: false - addresses: - - "192.168.123.1$i/26" - gateway4: "192.168.123.1" - nameservers: - search: [cluster.local] - addresses: [8.8.8.8] -EOT - - ( cd srv$i && genisoimage \ - -output seed.img \ - -volid cidata -rational-rock -joliet \ - user-data meta-data network-config - ) -done - -# Prepare system drive -if [ ! -f nocloud-amd64.raw ]; then - wget https://github.com/cozystack/cozystack/releases/latest/download/nocloud-amd64.raw.xz -O nocloud-amd64.raw.xz - rm -f nocloud-amd64.raw - xz --decompress nocloud-amd64.raw.xz -fi -for i in 1 2 3; do - cp nocloud-amd64.raw srv$i/system.img - qemu-img resize srv$i/system.img 20G -done - -# Prepare data drives -for i in 1 2 3; do - qemu-img create srv$i/data.img 100G -done - -# Prepare networking -for i in 1 2 3; do - ip link del cozy-srv$i || true - ip tuntap add dev cozy-srv$i mode tap - ip link set cozy-srv$i up - ip link set cozy-srv$i master cozy-br0 -done - -# Start VMs -for i in 1 2 3; do - qemu-system-x86_64 -machine type=pc,accel=kvm -cpu host -smp 8 -m 16384 \ - -device virtio-net,netdev=net0,mac=52:54:00:12:34:5$i -netdev tap,id=net0,ifname=cozy-srv$i,script=no,downscript=no \ - -drive file=srv$i/system.img,if=virtio,format=raw \ - -drive file=srv$i/seed.img,if=virtio,format=raw \ - -drive file=srv$i/data.img,if=virtio,format=raw \ - -display none -daemonize -pidfile srv$i/qemu.pid -done - -sleep 5 - -# Wait for VM to start up -timeout 60 sh -c 'until nc -nzv 192.168.123.11 50000 && nc -nzv 192.168.123.12 50000 && nc -nzv 192.168.123.13 50000; do sleep 1; done' - -cat > patch.yaml <<\EOT -machine: - kubelet: - nodeIP: - validSubnets: - - 192.168.123.0/24 - extraConfig: - maxPods: 512 - kernel: - modules: - - name: openvswitch - - name: drbd - parameters: - - usermode_helper=disabled - - name: zfs - - name: spl - registries: - mirrors: - docker.io: - endpoints: - - https://mirror.gcr.io - files: - - content: | - [plugins] - [plugins."io.containerd.grpc.v1.cri"] - device_ownership_from_security_context = true - path: /etc/cri/conf.d/20-customization.part - op: create - -cluster: - apiServer: - extraArgs: - oidc-issuer-url: "https://keycloak.example.org/realms/cozy" - oidc-client-id: "kubernetes" - oidc-username-claim: "preferred_username" - oidc-groups-claim: "groups" - network: - cni: - name: none - dnsDomain: cozy.local - podSubnets: - - 10.244.0.0/16 - serviceSubnets: - - 10.96.0.0/16 -EOT - -cat > patch-controlplane.yaml <<\EOT -machine: - nodeLabels: - node.kubernetes.io/exclude-from-external-load-balancers: - $patch: delete - network: - interfaces: - - interface: eth0 - vip: - ip: 192.168.123.10 -cluster: - allowSchedulingOnControlPlanes: true - controllerManager: - extraArgs: - bind-address: 0.0.0.0 - scheduler: - extraArgs: - bind-address: 0.0.0.0 - apiServer: - certSANs: - - 127.0.0.1 - proxy: - disabled: true - discovery: - enabled: false - etcd: - advertisedSubnets: - - 192.168.123.0/24 -EOT - -# Gen configuration -if [ ! -f secrets.yaml ]; then - talosctl gen secrets -fi - -rm -f controlplane.yaml worker.yaml talosconfig kubeconfig -talosctl gen config --with-secrets secrets.yaml cozystack https://192.168.123.10:6443 --config-patch=@patch.yaml --config-patch-control-plane @patch-controlplane.yaml -export TALOSCONFIG=$PWD/talosconfig - -# Apply configuration -talosctl apply -f controlplane.yaml -n 192.168.123.11 -e 192.168.123.11 -i -talosctl apply -f controlplane.yaml -n 192.168.123.12 -e 192.168.123.12 -i -talosctl apply -f controlplane.yaml -n 192.168.123.13 -e 192.168.123.13 -i - -# Wait for VM to be configured -timeout 60 sh -c 'until nc -nzv 192.168.123.11 50000 && nc -nzv 192.168.123.12 50000 && nc -nzv 192.168.123.13 50000; do sleep 1; done' - -# Bootstrap -timeout 10 sh -c 'until talosctl bootstrap -n 192.168.123.11 -e 192.168.123.11; do sleep 1; done' - -# Wait for etcd -timeout 180 sh -c 'until timeout -s 9 2 talosctl etcd members -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 2>&1; do sleep 1; done' -timeout 60 sh -c 'while talosctl etcd members -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 2>&1 | grep "rpc error"; do sleep 1; done' - -rm -f kubeconfig -talosctl kubeconfig kubeconfig -e 192.168.123.10 -n 192.168.123.10 -export KUBECONFIG=$PWD/kubeconfig - -# Wait for kubernetes nodes appear -timeout 60 sh -c 'until [ $(kubectl get node -o name | wc -l) = 3 ]; do sleep 1; done' -kubectl create ns cozy-system -o yaml | kubectl apply -f - -kubectl create -f - <<\EOT -apiVersion: v1 -kind: ConfigMap -metadata: - name: cozystack - namespace: cozy-system -data: - bundle-name: "paas-full" - ipv4-pod-cidr: "10.244.0.0/16" - ipv4-pod-gateway: "10.244.0.1" - ipv4-svc-cidr: "10.96.0.0/16" - ipv4-join-cidr: "100.64.0.0/16" - root-host: example.org - api-server-endpoint: https://192.168.123.10:6443 -EOT - -# -echo "$COZYSTACK_INSTALLER_YAML" | kubectl apply -f - - -# wait for cozystack pod to start -kubectl wait deploy --timeout=1m --for=condition=available -n cozy-system cozystack - -# wait for helmreleases appear -timeout 60 sh -c 'until kubectl get hr -A | grep cozy; do sleep 1; done' - -sleep 5 - -kubectl get hr -A | awk 'NR>1 {print "kubectl wait --timeout=15m --for=condition=ready -n " $1 " hr/" $2 " &"} END{print "wait"}' | sh -x - -# Wait for Cluster-API providers -timeout 60 sh -c 'until kubectl get deploy -n cozy-cluster-api capi-controller-manager capi-kamaji-controller-manager capi-kubeadm-bootstrap-controller-manager capi-operator-cluster-api-operator capk-controller-manager; do sleep 1; done' -kubectl wait deploy --timeout=1m --for=condition=available -n cozy-cluster-api capi-controller-manager capi-kamaji-controller-manager capi-kubeadm-bootstrap-controller-manager capi-operator-cluster-api-operator capk-controller-manager - -# Wait for linstor controller -kubectl wait deploy --timeout=5m --for=condition=available -n cozy-linstor linstor-controller - -# Wait for all linstor nodes become Online -timeout 60 sh -c 'until [ $(kubectl exec -n cozy-linstor deploy/linstor-controller -- linstor node list | grep -c Online) = 3 ]; do sleep 1; done' - -kubectl exec -n cozy-linstor deploy/linstor-controller -- linstor ps cdp zfs srv1 /dev/vdc --pool-name data --storage-pool data -kubectl exec -n cozy-linstor deploy/linstor-controller -- linstor ps cdp zfs srv2 /dev/vdc --pool-name data --storage-pool data -kubectl exec -n cozy-linstor deploy/linstor-controller -- linstor ps cdp zfs srv3 /dev/vdc --pool-name data --storage-pool data - -kubectl create -f- <<EOT ---- -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: local - annotations: - storageclass.kubernetes.io/is-default-class: "true" -provisioner: linstor.csi.linbit.com -parameters: - linstor.csi.linbit.com/storagePool: "data" - linstor.csi.linbit.com/layerList: "storage" - linstor.csi.linbit.com/allowRemoteVolumeAccess: "false" -volumeBindingMode: WaitForFirstConsumer -allowVolumeExpansion: true ---- -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: replicated -provisioner: linstor.csi.linbit.com -parameters: - linstor.csi.linbit.com/storagePool: "data" - linstor.csi.linbit.com/autoPlace: "3" - linstor.csi.linbit.com/layerList: "drbd storage" - linstor.csi.linbit.com/allowRemoteVolumeAccess: "true" - property.linstor.csi.linbit.com/DrbdOptions/auto-quorum: suspend-io - property.linstor.csi.linbit.com/DrbdOptions/Resource/on-no-data-accessible: suspend-io - property.linstor.csi.linbit.com/DrbdOptions/Resource/on-suspended-primary-outdated: force-secondary - property.linstor.csi.linbit.com/DrbdOptions/Net/rr-conflict: retry-connect -volumeBindingMode: WaitForFirstConsumer -allowVolumeExpansion: true -EOT -kubectl create -f- <<EOT ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: cozystack - namespace: cozy-metallb -spec: - ipAddressPools: - - cozystack ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: cozystack - namespace: cozy-metallb -spec: - addresses: - - 192.168.123.200-192.168.123.250 - autoAssign: true - avoidBuggyIPs: false -EOT - -# Wait for cozystack-api -kubectl wait --for=condition=Available apiservices v1alpha1.apps.cozystack.io --timeout=2m - -kubectl patch -n tenant-root tenants.apps.cozystack.io root --type=merge -p '{"spec":{ - "host": "example.org", - "ingress": true, - "monitoring": true, - "etcd": true, - "isolated": true -}}' - -# Wait for HelmRelease be created -timeout 60 sh -c 'until kubectl get hr -n tenant-root etcd ingress monitoring tenant-root; do sleep 1; done' - -# Wait for HelmReleases be installed -kubectl wait --timeout=2m --for=condition=ready -n tenant-root hr etcd ingress tenant-root - -if ! kubectl wait --timeout=2m --for=condition=ready -n tenant-root hr monitoring; then - flux reconcile hr monitoring -n tenant-root --force - kubectl wait --timeout=2m --for=condition=ready -n tenant-root hr monitoring -fi - -kubectl patch -n tenant-root ingresses.apps.cozystack.io ingress --type=merge -p '{"spec":{ - "dashboard": true -}}' - -# Wait for nginx-ingress-controller -timeout 60 sh -c 'until kubectl get deploy -n tenant-root root-ingress-controller; do sleep 1; done' -kubectl wait --timeout=5m --for=condition=available -n tenant-root deploy root-ingress-controller - -# Wait for etcd -kubectl wait --timeout=5m --for=jsonpath=.status.readyReplicas=3 -n tenant-root sts etcd - -# Wait for Victoria metrics -kubectl wait --timeout=5m --for=jsonpath=.status.updateStatus=operational -n tenant-root vmalert/vmalert-shortterm vmalertmanager/alertmanager -kubectl wait --timeout=5m --for=jsonpath=.status.updateStatus=operational -n tenant-root vlogs/generic -kubectl wait --timeout=5m --for=jsonpath=.status.clusterStatus=operational -n tenant-root vmcluster/shortterm vmcluster/longterm - -# Wait for grafana -kubectl wait --timeout=5m --for=condition=ready -n tenant-root clusters.postgresql.cnpg.io grafana-db -kubectl wait --timeout=5m --for=condition=available -n tenant-root deploy grafana-deployment - -# Get IP of nginx-ingress -ip=$(kubectl get svc -n tenant-root root-ingress-controller -o jsonpath='{.status.loadBalancer.ingress..ip}') - -# Check Grafana -curl -sS -k "https://$ip" -H 'Host: grafana.example.org' | grep Found - - -# Test OIDC -kubectl patch -n cozy-system cm/cozystack --type=merge -p '{"data":{ - "oidc-enabled": "true" -}}' - -timeout 120 sh -c 'until kubectl get hr -n cozy-keycloak keycloak keycloak-configure keycloak-operator; do sleep 1; done' -kubectl wait --timeout=10m --for=condition=ready -n cozy-keycloak hr keycloak keycloak-configure keycloak-operator diff --git a/hack/gen_versions_map.sh b/hack/gen_versions_map.sh index 5169bc2f..60ede8ba 100755 --- a/hack/gen_versions_map.sh +++ b/hack/gen_versions_map.sh @@ -16,13 +16,15 @@ if [ ! -f "$file" ] || [ ! -s "$file" ]; then exit 0 fi -miss_map=$(echo "$new_map" | awk 'NR==FNR { nm[$1 " " $2] = $3; next } { if (!($1 " " $2 in nm)) print $1, $2, $3}' - "$file") +miss_map=$(mktemp) +trap 'rm -f "$miss_map"' EXIT +echo -n "$new_map" | awk 'NR==FNR { nm[$1 " " $2] = $3; next } { if (!($1 " " $2 in nm)) print $1, $2, $3}' - "$file" > $miss_map # search accross all tags sorted by version search_commits=$(git ls-remote --tags origin | awk -F/ '$3 ~ /v[0-9]+.[0-9]+.[0-9]+/ {print}' | sort -k2,2 -rV | awk '{print $1}') resolved_miss_map=$( - echo "$miss_map" | while read -r chart version commit; do + while read -r chart version commit; do # if version is found in HEAD, it's HEAD if [ "$(awk '$1 == "version:" {print $2}' ./${chart}/Chart.yaml)" = "${version}" ]; then echo "$chart $version HEAD" @@ -56,7 +58,7 @@ resolved_miss_map=$( fi echo "$chart $version $found_tag" - done + done < $miss_map ) printf "%s\n" "$new_map" "$resolved_miss_map" | sort -k1,1 -k2,2 -V | awk '$1' > "$file" diff --git a/hack/package_chart.sh b/hack/package_chart.sh new file mode 100755 index 00000000..f8ab297f --- /dev/null +++ b/hack/package_chart.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +set -e + +usage() { + printf "%s\n" "Usage:" >&2 ; + printf -- "%s\n" '---' >&2 ; + printf "%s %s\n" "$0" "INPUT_DIR OUTPUT_DIR TMP_DIR [DEPENDENCY_DIR]" >&2 ; + printf -- "%s\n" '---' >&2 ; + printf "%s\n" "Takes a helm repository from INPUT_DIR, with an optional library repository in" >&2 ; + printf "%s\n" "DEPENDENCY_DIR, prepares a view of the git archive at select points in history" >&2 ; + printf "%s\n" "in TMP_DIR and packages helm charts, outputting the tarballs to OUTPUT_DIR" >&2 ; +} + +if [ "x$(basename $PWD)" != "xpackages" ] +then + echo "Error: This script must run from the ./packages/ directory" >&2 + echo >&2 + usage + exit 1 +fi + +if [ "x$#" != "x3" ] && [ "x$#" != "x4" ] +then + echo "Error: This script takes 3 or 4 arguments" >&2 + echo "Got $# arguments:" "$@" >&2 + echo >&2 + usage + exit 1 +fi + +input_dir=$1 +output_dir=$2 +tmp_dir=$3 + +if [ "x$#" = "x4" ] +then + dependency_dir=$4 +fi + +rm -rf "${output_dir:?}" +mkdir -p "${output_dir}" +while read package _ commit +do + # this lets devs build the packages from a dirty repo for quick local testing + if [ "x$commit" = "xHEAD" ] + then + helm package "${input_dir}/${package}" -d "${output_dir}" + continue + fi + git archive --format tar "${commit}" "${input_dir}/${package}" | tar -xf- -C "${tmp_dir}/" + + # the library chart is not present in older commits and git archive doesn't fail gracefully if the path is not found + if [ "x${dependency_dir}" != "x" ] && git ls-tree --name-only "${commit}" "${dependency_dir}" | grep -qx "${dependency_dir}" + then + git archive --format tar "${commit}" "${dependency_dir}" | tar -xf- -C "${tmp_dir}/" + fi + helm package "${tmp_dir}/${input_dir}/${package}" -d "${output_dir}" + rm -rf "${tmp_dir:?}/${input_dir:?}/${package:?}" + if [ "x${dependency_dir}" != "x" ] + then + rm -rf "${tmp_dir:?}/${dependency_dir:?}" + fi +done < "${input_dir}/versions_map" +helm repo index "${output_dir}" diff --git a/hack/testdata/http-cache/check.sh b/hack/testdata/http-cache/check.sh deleted file mode 100644 index 61c7ebff..00000000 --- a/hack/testdata/http-cache/check.sh +++ /dev/null @@ -1 +0,0 @@ -return 0 diff --git a/hack/testdata/http-cache/values.yaml b/hack/testdata/http-cache/values.yaml deleted file mode 100644 index 2674c1c3..00000000 --- a/hack/testdata/http-cache/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -endpoints: - - 8.8.8.8:443 diff --git a/hack/testdata/kubernetes/check.sh b/hack/testdata/kubernetes/check.sh deleted file mode 100644 index 61c7ebff..00000000 --- a/hack/testdata/kubernetes/check.sh +++ /dev/null @@ -1 +0,0 @@ -return 0 diff --git a/hack/testdata/kubernetes/values.yaml b/hack/testdata/kubernetes/values.yaml deleted file mode 100644 index 71e290c5..00000000 --- a/hack/testdata/kubernetes/values.yaml +++ /dev/null @@ -1,62 +0,0 @@ -## @section Common parameters - -## @param host The hostname used to access the Kubernetes cluster externally (defaults to using the cluster name as a subdomain for the tenant host). -## @param controlPlane.replicas Number of replicas for Kubernetes contorl-plane components -## @param storageClass StorageClass used to store user data -## -host: "" -controlPlane: - replicas: 2 -storageClass: replicated - -## @param nodeGroups [object] nodeGroups configuration -## -nodeGroups: - md0: - minReplicas: 0 - maxReplicas: 10 - instanceType: "u1.medium" - ephemeralStorage: 20Gi - roles: - - ingress-nginx - - resources: - cpu: "" - memory: "" - -## @section Cluster Addons -## -addons: - - ## Cert-manager: automatically creates and manages SSL/TLS certificate - ## - certManager: - ## @param addons.certManager.enabled Enables the cert-manager - ## @param addons.certManager.valuesOverride Custom values to override - enabled: true - valuesOverride: {} - - ## Ingress-NGINX Controller - ## - ingressNginx: - ## @param addons.ingressNginx.enabled Enable Ingress-NGINX controller (expect nodes with 'ingress-nginx' role) - ## @param addons.ingressNginx.valuesOverride Custom values to override - ## - enabled: true - ## @param addons.ingressNginx.hosts List of domain names that should be passed through to the cluster by upper cluster - ## e.g: - ## hosts: - ## - example.org - ## - foo.example.net - ## - hosts: [] - valuesOverride: {} - - ## Flux CD - ## - fluxcd: - ## @param addons.fluxcd.enabled Enables Flux CD - ## @param addons.fluxcd.valuesOverride Custom values to override - ## - enabled: true - valuesOverride: {} diff --git a/hack/testdata/nats/check.sh b/hack/testdata/nats/check.sh deleted file mode 100644 index 61c7ebff..00000000 --- a/hack/testdata/nats/check.sh +++ /dev/null @@ -1 +0,0 @@ -return 0 diff --git a/hack/testdata/nats/values.yaml b/hack/testdata/nats/values.yaml deleted file mode 100644 index 7044641c..00000000 --- a/hack/testdata/nats/values.yaml +++ /dev/null @@ -1,10 +0,0 @@ - -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @param replicas Persistent Volume size for NATS -## @param storageClass StorageClass used to store the data -## -external: false -replicas: 2 -storageClass: "" diff --git a/hack/testdata/tenant/check.sh b/hack/testdata/tenant/check.sh deleted file mode 100644 index 61c7ebff..00000000 --- a/hack/testdata/tenant/check.sh +++ /dev/null @@ -1 +0,0 @@ -return 0 diff --git a/hack/testdata/tenant/values.yaml b/hack/testdata/tenant/values.yaml deleted file mode 100644 index 3e75d05b..00000000 --- a/hack/testdata/tenant/values.yaml +++ /dev/null @@ -1,6 +0,0 @@ -host: "" -etcd: false -monitoring: false -ingress: false -seaweedfs: false -isolated: true diff --git a/internal/controller/tenant_helm_reconciler.go b/internal/controller/tenant_helm_reconciler.go new file mode 100644 index 00000000..402ff5ba --- /dev/null +++ b/internal/controller/tenant_helm_reconciler.go @@ -0,0 +1,158 @@ +package controller + +import ( + "context" + "fmt" + "strings" + "time" + + e "errors" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + "gopkg.in/yaml.v2" + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +type TenantHelmReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *TenantHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + hr := &helmv2.HelmRelease{} + if err := r.Get(ctx, req.NamespacedName, hr); err != nil { + if errors.IsNotFound(err) { + return ctrl.Result{}, nil + } + logger.Error(err, "unable to fetch HelmRelease") + return ctrl.Result{}, err + } + + if !strings.HasPrefix(hr.Name, "tenant-") { + return ctrl.Result{}, nil + } + + if len(hr.Status.Conditions) == 0 || hr.Status.Conditions[0].Type != "Ready" { + return ctrl.Result{}, nil + } + + if len(hr.Status.History) == 0 { + logger.Info("no history in HelmRelease status", "name", hr.Name) + return ctrl.Result{}, nil + } + + if hr.Status.History[0].Status != "deployed" { + return ctrl.Result{}, nil + } + + newDigest := hr.Status.History[0].Digest + var hrList helmv2.HelmReleaseList + childNamespace := getChildNamespace(hr.Namespace, hr.Name) + if childNamespace == "tenant-root" && hr.Name == "tenant-root" { + if hr.Spec.Values == nil { + logger.Error(e.New("hr.Spec.Values is nil"), "cant annotate tenant-root ns") + return ctrl.Result{}, nil + } + err := annotateTenantRootNs(*hr.Spec.Values, r.Client) + if err != nil { + logger.Error(err, "cant annotate tenant-root ns") + return ctrl.Result{}, nil + } + logger.Info("namespace 'tenant-root' annotated") + } + + if err := r.List(ctx, &hrList, client.InNamespace(childNamespace)); err != nil { + logger.Error(err, "unable to list HelmReleases in namespace", "namespace", hr.Name) + return ctrl.Result{}, err + } + + for _, item := range hrList.Items { + if item.Name == hr.Name { + continue + } + oldDigest := item.GetAnnotations()["cozystack.io/tenant-config-digest"] + if oldDigest == newDigest { + continue + } + patchTarget := item.DeepCopy() + + if patchTarget.Annotations == nil { + patchTarget.Annotations = map[string]string{} + } + ts := time.Now().Format(time.RFC3339Nano) + + patchTarget.Annotations["cozystack.io/tenant-config-digest"] = newDigest + patchTarget.Annotations["reconcile.fluxcd.io/forceAt"] = ts + patchTarget.Annotations["reconcile.fluxcd.io/requestedAt"] = ts + + patch := client.MergeFrom(item.DeepCopy()) + if err := r.Patch(ctx, patchTarget, patch); err != nil { + logger.Error(err, "failed to patch HelmRelease", "name", patchTarget.Name) + continue + } + + logger.Info("patched HelmRelease with new digest", "name", patchTarget.Name, "digest", newDigest, "version", hr.Status.History[0].Version) + } + + return ctrl.Result{}, nil +} + +func (r *TenantHelmReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&helmv2.HelmRelease{}). + Complete(r) +} + +func getChildNamespace(currentNamespace, hrName string) string { + tenantName := strings.TrimPrefix(hrName, "tenant-") + + switch { + case currentNamespace == "tenant-root" && hrName == "tenant-root": + // 1) root tenant inside root namespace + return "tenant-root" + + case currentNamespace == "tenant-root": + // 2) any other tenant in root namespace + return fmt.Sprintf("tenant-%s", tenantName) + + default: + // 3) tenant in a dedicated namespace + return fmt.Sprintf("%s-%s", currentNamespace, tenantName) + } +} + +func annotateTenantRootNs(values apiextensionsv1.JSON, c client.Client) error { + var data map[string]interface{} + if err := yaml.Unmarshal(values.Raw, &data); err != nil { + return fmt.Errorf("failed to parse HelmRelease values: %w", err) + } + + host, ok := data["host"].(string) + if !ok || host == "" { + return fmt.Errorf("host field not found or not a string") + } + + var ns corev1.Namespace + if err := c.Get(context.TODO(), client.ObjectKey{Name: "tenant-root"}, &ns); err != nil { + return fmt.Errorf("failed to get namespace tenant-root: %w", err) + } + + if ns.Annotations == nil { + ns.Annotations = map[string]string{} + } + ns.Annotations["namespace.cozystack.io/host"] = host + + if err := c.Update(context.TODO(), &ns); err != nil { + return fmt.Errorf("failed to update namespace: %w", err) + } + + return nil +} diff --git a/internal/controller/workload_controller.go b/internal/controller/workload_controller.go index 7b7f8406..3624e0e1 100644 --- a/internal/controller/workload_controller.go +++ b/internal/controller/workload_controller.go @@ -39,6 +39,15 @@ func (r *WorkloadReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } t := getMonitoredObject(w) + + if t == nil { + err = r.Delete(ctx, w) + if err != nil { + logger.Error(err, "failed to delete workload") + } + return ctrl.Result{}, err + } + err = r.Get(ctx, types.NamespacedName{Name: t.GetName(), Namespace: t.GetNamespace()}, t) // found object, nothing to do @@ -68,20 +77,23 @@ func (r *WorkloadReconciler) SetupWithManager(mgr ctrl.Manager) error { } func getMonitoredObject(w *cozyv1alpha1.Workload) client.Object { - if strings.HasPrefix(w.Name, "pvc-") { + switch { + case strings.HasPrefix(w.Name, "pvc-"): obj := &corev1.PersistentVolumeClaim{} obj.Name = strings.TrimPrefix(w.Name, "pvc-") obj.Namespace = w.Namespace return obj - } - if strings.HasPrefix(w.Name, "svc-") { + case strings.HasPrefix(w.Name, "svc-"): obj := &corev1.Service{} obj.Name = strings.TrimPrefix(w.Name, "svc-") obj.Namespace = w.Namespace return obj + case strings.HasPrefix(w.Name, "pod-"): + obj := &corev1.Pod{} + obj.Name = strings.TrimPrefix(w.Name, "pod-") + obj.Namespace = w.Namespace + return obj } - obj := &corev1.Pod{} - obj.Name = w.Name - obj.Namespace = w.Namespace + var obj client.Object return obj } diff --git a/internal/controller/workload_controller_test.go b/internal/controller/workload_controller_test.go new file mode 100644 index 00000000..816c135e --- /dev/null +++ b/internal/controller/workload_controller_test.go @@ -0,0 +1,26 @@ +package controller + +import ( + "testing" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +func TestUnprefixedMonitoredObjectReturnsNil(t *testing.T) { + w := &cozyv1alpha1.Workload{} + w.Name = "unprefixed-name" + obj := getMonitoredObject(w) + if obj != nil { + t.Errorf(`getMonitoredObject(&Workload{Name: "%s"}) == %v, want nil`, w.Name, obj) + } +} + +func TestPodMonitoredObject(t *testing.T) { + w := &cozyv1alpha1.Workload{} + w.Name = "pod-mypod" + obj := getMonitoredObject(w) + if pod, ok := obj.(*corev1.Pod); !ok || pod.Name != "mypod" { + t.Errorf(`getMonitoredObject(&Workload{Name: "%s"}) == %v, want &Pod{Name: "mypod"}`, w.Name, obj) + } +} diff --git a/internal/controller/workloadmonitor_controller.go b/internal/controller/workloadmonitor_controller.go index 330d1dc5..a1d4a501 100644 --- a/internal/controller/workloadmonitor_controller.go +++ b/internal/controller/workloadmonitor_controller.go @@ -212,15 +212,12 @@ func (r *WorkloadMonitorReconciler) reconcilePodForMonitor( ) error { logger := log.FromContext(ctx) - // Combine both init containers and normal containers to sum resources properly - combinedContainers := append(pod.Spec.InitContainers, pod.Spec.Containers...) - - // totalResources will store the sum of all container resource limits + // totalResources will store the sum of all container resource requests totalResources := make(map[string]resource.Quantity) - // Iterate over all containers to aggregate their Limits - for _, container := range combinedContainers { - for name, qty := range container.Resources.Limits { + // Iterate over all containers to aggregate their requests + for _, container := range pod.Spec.Containers { + for name, qty := range container.Resources.Requests { if existing, exists := totalResources[name.String()]; exists { existing.Add(qty) totalResources[name.String()] = existing @@ -249,7 +246,7 @@ func (r *WorkloadMonitorReconciler) reconcilePodForMonitor( workload := &cozyv1alpha1.Workload{ ObjectMeta: metav1.ObjectMeta{ - Name: pod.Name, + Name: fmt.Sprintf("pod-%s", pod.Name), Namespace: pod.Namespace, }, } diff --git a/packages/apps/Makefile b/packages/apps/Makefile index de61e3fa..c22b2eec 100644 --- a/packages/apps/Makefile +++ b/packages/apps/Makefile @@ -1,14 +1,8 @@ -OUT=../../_out/repos/apps -TMP=../../_out/repos/apps/historical +OUT=../_out/repos/apps +TMP := $(shell mktemp -d) repo: - rm -rf "$(OUT)" - mkdir -p "$(OUT)" - awk '$$3 != "HEAD" {print "mkdir -p $(TMP)/" $$1 "-" $$2}' versions_map | sh -ex - awk '$$3 != "HEAD" {print "git archive " $$3 " " $$1 " | tar -xf- --strip-components=1 -C $(TMP)/" $$1 "-" $$2 }' versions_map | sh -ex - helm package -d "$(OUT)" $$(find . $(TMP) -mindepth 2 -maxdepth 2 -name Chart.yaml | awk 'sub("/Chart.yaml", "")' | sort -V) - cd "$(OUT)" && helm repo index . --url http://cozystack.cozy-system.svc/repos/apps - rm -rf "$(TMP)" + cd .. && ../hack/package_chart.sh apps $(OUT) $(TMP) library fix-chartnames: find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed "s/^name: .*/name: $$i/" "$$i/Chart.yaml"; done diff --git a/packages/apps/bucket/README.md b/packages/apps/bucket/README.md new file mode 100644 index 00000000..89749b1d --- /dev/null +++ b/packages/apps/bucket/README.md @@ -0,0 +1,3 @@ +# S3 bucket + +## Parameters diff --git a/packages/apps/bucket/templates/helmrelease.yaml b/packages/apps/bucket/templates/helmrelease.yaml index ac014e03..d51e3b36 100644 --- a/packages/apps/bucket/templates/helmrelease.yaml +++ b/packages/apps/bucket/templates/helmrelease.yaml @@ -11,7 +11,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system - version: '*' + version: '>= 0.0.0-0' interval: 1m0s timeout: 5m0s values: diff --git a/packages/apps/bucket/values.schema.json b/packages/apps/bucket/values.schema.json new file mode 100644 index 00000000..decc79aa --- /dev/null +++ b/packages/apps/bucket/values.schema.json @@ -0,0 +1,5 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/packages/apps/bucket/values.yaml b/packages/apps/bucket/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/apps/bucket/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/apps/clickhouse/Chart.yaml b/packages/apps/clickhouse/Chart.yaml index 0466800b..bfb34b34 100644 --- a/packages/apps/clickhouse/Chart.yaml +++ b/packages/apps/clickhouse/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.7.0 +version: 0.9.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/clickhouse/Makefile b/packages/apps/clickhouse/Makefile index 10460cb0..ae59ae22 100644 --- a/packages/apps/clickhouse/Makefile +++ b/packages/apps/clickhouse/Makefile @@ -7,8 +7,10 @@ generate: readme-generator -v values.yaml -s values.schema.json -r README.md image: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/clickhouse-backup \ + docker buildx build images/clickhouse-backup \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/clickhouse-backup:$(call settag,$(CLICKHOUSE_BACKUP_TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/clickhouse-backup:latest \ --cache-to type=inline \ diff --git a/packages/apps/clickhouse/charts/cozy-lib b/packages/apps/clickhouse/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/apps/clickhouse/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/apps/clickhouse/images/clickhouse-backup.tag b/packages/apps/clickhouse/images/clickhouse-backup.tag index 82eb1df5..1972c5d9 100644 --- a/packages/apps/clickhouse/images/clickhouse-backup.tag +++ b/packages/apps/clickhouse/images/clickhouse-backup.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/clickhouse-backup:0.7.0@sha256:3faf7a4cebf390b9053763107482de175aa0fdb88c1e77424fd81100b1c3a205 +ghcr.io/cozystack/cozystack/clickhouse-backup:0.9.0@sha256:3faf7a4cebf390b9053763107482de175aa0fdb88c1e77424fd81100b1c3a205 diff --git a/packages/apps/clickhouse/templates/_resources.tpl b/packages/apps/clickhouse/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/clickhouse/templates/_resources.tpl +++ b/packages/apps/clickhouse/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/clickhouse/templates/clickhouse.yaml b/packages/apps/clickhouse/templates/clickhouse.yaml index dd4b0fdb..dd97188d 100644 --- a/packages/apps/clickhouse/templates/clickhouse.yaml +++ b/packages/apps/clickhouse/templates/clickhouse.yaml @@ -122,9 +122,9 @@ spec: - name: clickhouse image: clickhouse/clickhouse-server:24.9.2.42 {{- if .Values.resources }} - resources: {{- toYaml .Values.resources | nindent 16 }} + resources: {{- include "cozy-lib.resources.sanitize" .Values.resources | nindent 16 }} {{- else if ne .Values.resourcesPreset "none" }} - resources: {{- include "resources.preset" (dict "type" .Values.resourcesPreset "Release" .Release) | nindent 16 }} + resources: {{- include "cozy-lib.resources.preset" .Values.resourcesPreset | nindent 16 }} {{- end }} volumeMounts: - name: data-volume-template diff --git a/packages/apps/ferretdb/Chart.yaml b/packages/apps/ferretdb/Chart.yaml index fa41dcbd..273d9d97 100644 --- a/packages/apps/ferretdb/Chart.yaml +++ b/packages/apps/ferretdb/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.5.0 +version: 0.6.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/ferretdb/images/postgres-backup.tag b/packages/apps/ferretdb/images/postgres-backup.tag index 631a088b..e47315f2 100644 --- a/packages/apps/ferretdb/images/postgres-backup.tag +++ b/packages/apps/ferretdb/images/postgres-backup.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/postgres-backup:0.10.0@sha256:10179ed56457460d95cd5708db2a00130901255fa30c4dd76c65d2ef5622b61f +ghcr.io/cozystack/cozystack/postgres-backup:0.11.0@sha256:10179ed56457460d95cd5708db2a00130901255fa30c4dd76c65d2ef5622b61f diff --git a/packages/apps/ferretdb/templates/_resources.tpl b/packages/apps/ferretdb/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/ferretdb/templates/_resources.tpl +++ b/packages/apps/ferretdb/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/http-cache/Chart.yaml b/packages/apps/http-cache/Chart.yaml index 2224053c..151b3b42 100644 --- a/packages/apps/http-cache/Chart.yaml +++ b/packages/apps/http-cache/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.0 +version: 0.5.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/http-cache/Makefile b/packages/apps/http-cache/Makefile index 833a817d..c8270993 100644 --- a/packages/apps/http-cache/Makefile +++ b/packages/apps/http-cache/Makefile @@ -6,8 +6,10 @@ include ../../../scripts/package.mk image: image-nginx image-nginx: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/nginx-cache \ + docker buildx build images/nginx-cache \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/nginx-cache:$(call settag,$(NGINX_CACHE_TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/nginx-cache:latest \ --cache-to type=inline \ diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index e8e62c73..f5106b42 100644 --- a/packages/apps/http-cache/images/nginx-cache.tag +++ b/packages/apps/http-cache/images/nginx-cache.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/nginx-cache:0.4.0@sha256:bef7344da098c4dc400a9e20ffad10ac991df67d09a30026207454abbc91f28b +ghcr.io/cozystack/cozystack/nginx-cache:0.5.0@sha256:158c35dd6a512bd14e86a423be5c8c7ca91ac71999c73cce2714e4db60a2db43 diff --git a/packages/apps/http-cache/images/nginx-cache/Dockerfile b/packages/apps/http-cache/images/nginx-cache/Dockerfile index f121a3ab..2425acf7 100644 --- a/packages/apps/http-cache/images/nginx-cache/Dockerfile +++ b/packages/apps/http-cache/images/nginx-cache/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 as stage +FROM ubuntu:22.04 AS stage ARG NGINX_VERSION=1.25.3 ARG IP2LOCATION_C_VERSION=8.6.1 @@ -9,11 +9,15 @@ ARG FIFTYONEDEGREES_NGINX_VERSION=3.2.21.1 ARG NGINX_CACHE_PURGE_VERSION=2.5.3 ARG NGINX_VTS_VERSION=0.2.2 +ARG TARGETOS +ARG TARGETARCH + # Install required packages for development -RUN apt-get update -q \ - && apt-get install -yq \ +RUN apt update -q \ + && apt install -yq --no-install-recommends \ + ca-certificates \ unzip \ - autoconf \ + automake \ build-essential \ libtool \ libpcre3 \ @@ -68,7 +72,7 @@ RUN checkinstall \ --default \ --pkgname=ip2location-c \ --pkgversion=${IP2LOCATION_C_VERSION} \ - --pkgarch=amd64 \ + --pkgarch=${TARGETARCH} \ --pkggroup=lib \ --pkgsource="https://github.com/chrislim2888/IP2Location-C-Library" \ --maintainer="Eduard Generalov <eduard@generalov.net>" \ @@ -97,7 +101,7 @@ RUN checkinstall \ --default \ --pkgname=ip2proxy-c \ --pkgversion=${IP2PROXY_C_VERSION} \ - --pkgarch=amd64 \ + --pkgarch=${TARGETARCH} \ --pkggroup=lib \ --pkgsource="https://github.com/ip2location/ip2proxy-c" \ --maintainer="Eduard Generalov <eduard@generalov.net>" \ @@ -144,7 +148,7 @@ RUN checkinstall \ --default \ --pkgname=nginx \ --pkgversion=$VERS \ - --pkgarch=amd64 \ + --pkgarch=${TARGETARCH} \ --pkggroup=web \ --provides=nginx \ --requires=ip2location-c,ip2proxy-c,libssl3,libc-bin,libc6,libzstd1,libpcre++0v5,libpcre16-3,libpcre2-8-0,libpcre3,libpcre32-3,libpcrecpp0v5,libmaxminddb0 \ @@ -165,10 +169,9 @@ COPY nginx-reloader.sh /usr/bin/nginx-reloader.sh RUN set -x \ && groupadd --system --gid 101 nginx \ && useradd --system --gid nginx --no-create-home --home /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ - && apt update \ - && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates inotify-tools \ - && apt -y install /packages/*.deb \ - && apt-get clean \ + && apt update -q \ + && apt install -yq --no-install-recommends --no-install-suggests gnupg1 ca-certificates inotify-tools \ + && apt install -y /packages/*.deb \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /var/lib/nginx /var/log/nginx \ && ln -sf /dev/stdout /var/log/nginx/access.log \ diff --git a/packages/apps/http-cache/templates/_resources.tpl b/packages/apps/http-cache/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/http-cache/templates/_resources.tpl +++ b/packages/apps/http-cache/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/kafka/Chart.yaml b/packages/apps/kafka/Chart.yaml index d4e910d4..00213f83 100644 --- a/packages/apps/kafka/Chart.yaml +++ b/packages/apps/kafka/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.5.0 +version: 0.6.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/kafka/templates/_resources.tpl b/packages/apps/kafka/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/kafka/templates/_resources.tpl +++ b/packages/apps/kafka/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/kubernetes/Chart.yaml b/packages/apps/kubernetes/Chart.yaml index cc8b5a83..2164da8e 100644 --- a/packages/apps/kubernetes/Chart.yaml +++ b/packages/apps/kubernetes/Chart.yaml @@ -16,10 +16,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.18.1 +version: 0.20.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.30.1" +appVersion: 1.32.4 diff --git a/packages/apps/kubernetes/Makefile b/packages/apps/kubernetes/Makefile index 03799c2b..10898e65 100644 --- a/packages/apps/kubernetes/Makefile +++ b/packages/apps/kubernetes/Makefile @@ -1,4 +1,4 @@ -UBUNTU_CONTAINER_DISK_TAG = v1.30.1 +KUBERNETES_VERSION = v1.32 KUBERNETES_PKG_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) include ../../../scripts/common-envs.mk @@ -6,27 +6,36 @@ include ../../../scripts/package.mk generate: readme-generator -v values.yaml -s values.schema.json -r README.md + yq -o json -i '.properties.controlPlane.properties.apiServer.properties.resourcesPreset.enum = ["none","nano","micro","small","medium","large","xlarge","2xlarge"]' values.schema.json + yq -o json -i '.properties.controlPlane.properties.controllerManager.properties.resourcesPreset.enum = ["none","nano","micro","small","medium","large","xlarge","2xlarge"]' values.schema.json + yq -o json -i '.properties.controlPlane.properties.scheduler.properties.resourcesPreset.enum = ["none","nano","micro","small","medium","large","xlarge","2xlarge"]' values.schema.json + yq -o json -i '.properties.controlPlane.properties.konnectivity.properties.server.properties.resourcesPreset.enum = ["none","nano","micro","small","medium","large","xlarge","2xlarge"]' values.schema.json image: image-ubuntu-container-disk image-kubevirt-cloud-provider image-kubevirt-csi-driver image-cluster-autoscaler image-ubuntu-container-disk: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/ubuntu-container-disk \ + docker buildx build images/ubuntu-container-disk \ --provenance false \ - --tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(UBUNTU_CONTAINER_DISK_TAG)) \ - --tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(UBUNTU_CONTAINER_DISK_TAG)-$(TAG)) \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ + --build-arg KUBERNETES_VERSION=${KUBERNETES_VERSION} \ + --tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION)) \ + --tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION)-$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/ubuntu-container-disk:latest \ --cache-to type=inline \ --metadata-file images/ubuntu-container-disk.json \ --push=$(PUSH) \ --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ --load=$(LOAD) - echo "$(REGISTRY)/ubuntu-container-disk:$(call settag,$(UBUNTU_CONTAINER_DISK_TAG))@$$(yq e '."containerimage.digest"' images/ubuntu-container-disk.json -o json -r)" \ + echo "$(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION))@$$(yq e '."containerimage.digest"' images/ubuntu-container-disk.json -o json -r)" \ > images/ubuntu-container-disk.tag rm -f images/ubuntu-container-disk.json image-kubevirt-cloud-provider: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/kubevirt-cloud-provider \ + docker buildx build images/kubevirt-cloud-provider \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/kubevirt-cloud-provider:$(call settag,$(KUBERNETES_PKG_TAG)) \ --tag $(REGISTRY)/kubevirt-cloud-provider:$(call settag,$(KUBERNETES_PKG_TAG)-$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/kubevirt-cloud-provider:latest \ @@ -40,8 +49,10 @@ image-kubevirt-cloud-provider: rm -f images/kubevirt-cloud-provider.json image-kubevirt-csi-driver: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/kubevirt-csi-driver \ + docker buildx build images/kubevirt-csi-driver \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/kubevirt-csi-driver:$(call settag,$(KUBERNETES_PKG_TAG)) \ --tag $(REGISTRY)/kubevirt-csi-driver:$(call settag,$(KUBERNETES_PKG_TAG)-$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/kubevirt-csi-driver:latest \ @@ -56,8 +67,10 @@ image-kubevirt-csi-driver: image-cluster-autoscaler: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/cluster-autoscaler \ + docker buildx build images/cluster-autoscaler \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/cluster-autoscaler:$(call settag,$(KUBERNETES_PKG_TAG)) \ --tag $(REGISTRY)/cluster-autoscaler:$(call settag,$(KUBERNETES_PKG_TAG)-$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/cluster-autoscaler:latest \ diff --git a/packages/apps/kubernetes/README.md b/packages/apps/kubernetes/README.md index bbc55cfd..8cd62b25 100644 --- a/packages/apps/kubernetes/README.md +++ b/packages/apps/kubernetes/README.md @@ -1,49 +1,199 @@ # Managed Kubernetes Service -## Overview +## Managed Kubernetes in Cozystack -The Managed Kubernetes Service offers a streamlined solution for efficiently managing server workloads. Kubernetes has emerged as the industry standard, providing a unified and accessible API, primarily utilizing YAML for configuration. This means that teams can easily understand and work with Kubernetes, streamlining infrastructure management. +Whenever you want to deploy a custom containerized application in Cozystack, it's best to deploy it to a managed Kubernetes cluster. -The Kubernetes leverages robust software design patterns, enabling continuous recovery in any scenario through the reconciliation method. Additionally, it ensures seamless scaling across a multitude of servers, addressing the challenges posed by complex and outdated APIs found in traditional virtualization platforms. This managed service eliminates the need for developing custom solutions or modifying source code, saving valuable time and effort. +Cozystack deploys and manages Kubernetes-as-a-service as standalone applications within each tenant’s isolated environment. +In Cozystack, such clusters are named tenant Kubernetes clusters, while the base Cozystack cluster is called a management or root cluster. +Tenant clusters are fully separated from the management cluster and are intended for deploying tenant-specific or customer-developed applications. -## Deployment Details +Within a tenant cluster, users can take advantage of LoadBalancer services and easily provision physical volumes as needed. +The control-plane operates within containers, while the worker nodes are deployed as virtual machines, all seamlessly managed by the application. -The managed Kubernetes service deploys a standard Kubernetes cluster utilizing the Cluster API, Kamaji as control-plane provicer and the KubeVirt infrastructure provider. This ensures a consistent and reliable setup for workloads. +## Why Use a Managed Kubernetes Cluster? -Within this cluster, users can take advantage of LoadBalancer services and easily provision physical volumes as needed. The control-plane operates within containers, while the worker nodes are deployed as virtual machines, all seamlessly managed by the application. +Kubernetes has emerged as the industry standard, providing a unified and accessible API, primarily utilizing YAML for configuration. +This means that teams can easily understand and work with Kubernetes, streamlining infrastructure management. -- Docs: https://github.com/clastix/kamaji -- Docs: https://cluster-api.sigs.k8s.io/ -- GitHub: https://github.com/clastix/kamaji -- GitHub: https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt -- GitHub: https://github.com/kubevirt/csi-driver +Kubernetes leverages robust software design patterns, enabling continuous recovery in any scenario through the reconciliation method. +Additionally, it ensures seamless scaling across a multitude of servers, +addressing the challenges posed by complex and outdated APIs found in traditional virtualization platforms. +This managed service eliminates the need for developing custom solutions or modifying source code, saving valuable time and effort. +The Managed Kubernetes Service in Cozystack offers a streamlined solution for efficiently managing server workloads. -## How-Tos +## Starting Work -How to access to deployed cluster: +Once the tenant Kubernetes cluster is ready, you can get a kubeconfig file to work with it. +It can be done via UI or a `kubectl` request: -``` -kubectl get secret -n <namespace> kubernetes-<clusterName>-admin-kubeconfig -o go-template='{{ printf "%s\n" (index .data "super-admin.conf" | base64decode) }}' > test +- Open the Cozystack dashboard, switch to your tenant, find and open the application page. Copy one of the config files from the **Secrets** section. +- Run the following command (using the management cluster kubeconfig): + + ```bash + kubectl get secret -n tenant-<name> kubernetes-<clusterName>-admin-kubeconfig -o go-template='{{ printf "%s\n" (index .data "admin.conf" | base64decode) }}' > admin.conf + ``` + +There are several kubeconfig options available: + +- `admin.conf` — The standard kubeconfig for accessing your new cluster. + You can create additional Kubernetes users using this configuration. +- `admin.svc` — Same token as `admin.conf`, but with the API server address set to the internal service name. + Use it for applications running inside the cluster that need API access. +- `super-admin.conf` — Similar to `admin.conf`, but with extended administrative permissions. + Intended for troubleshooting and cluster maintenance tasks. +- `super-admin.svc` — Same as `super-admin.conf`, but pointing to the internal API server address. + +## Implementation Details + +A tenant Kubernetes cluster in Cozystack is essentially Kubernetes-in-Kubernetes. +Deploying it involves the following components: + +- **Kamaji Control Plane**: [Kamaji](https://kamaji.clastix.io/) is an open-source project that facilitates the deployment + of Kubernetes control planes as pods within a root cluster. + Each control plane pod includes essential components like `kube-apiserver`, `controller-manager`, and `scheduler`, + allowing for efficient multi-tenancy and resource utilization. + +- **Etcd Cluster**: A dedicated etcd cluster is deployed using Ænix's [etcd-operator](https://github.com/aenix-io/etcd-operator). + It provides reliable and scalable key-value storage for the Kubernetes control plane. + +- **Worker Nodes**: Virtual Machines are provisioned to serve as worker nodes using KubeVirt. + These nodes are configured to join the tenant Kubernetes cluster, enabling the deployment and management of workloads. + +- **Cluster API**: Cozystack is using the [Kubernetes Cluster API](https://cluster-api.sigs.k8s.io/) to provision the components of a cluster. + +This architecture ensures isolated, scalable, and efficient tenant Kubernetes environments. + +See the reference for components utilized in this service: + +- [Kamaji Control Plane](https://kamaji.clastix.io) +- [Kamaji — Cluster API](https://kamaji.clastix.io/cluster-api/) +- [github.com/clastix/kamaji](https://github.com/clastix/kamaji) +- [KubeVirt](https://kubevirt.io/) +- [github.com/kubevirt/kubevirt](https://github.com/kubevirt/kubevirt) +- [github.com/aenix-io/etcd-operator](https://github.com/aenix-io/etcd-operator) +- [Kubernetes Cluster API](https://cluster-api.sigs.k8s.io/) +- [github.com/kubernetes-sigs/cluster-api-provider-kubevirt](https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt) +- [github.com/kubevirt/csi-driver](https://github.com/kubevirt/csi-driver) + +## Parameters + +### Common Parameters + +| Name | Description | Value | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------ | +| `host` | Hostname used to access the Kubernetes cluster externally. Defaults to `<cluster-name>.<tenant-host>` when empty. | `""` | +| `controlPlane.replicas` | Number of replicas for Kubernetes control-plane components. | `2` | +| `storageClass` | StorageClass used to store user data. | `replicated` | +| `nodeGroups` | nodeGroups configuration | `{}` | + +### Cluster Addons + +| Name | Description | Value | +| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `addons.certManager.enabled` | Enable cert-manager, which automatically creates and manages SSL/TLS certificates. | `false` | +| `addons.certManager.valuesOverride` | Custom values to override | `{}` | +| `addons.cilium.valuesOverride` | Custom values to override | `{}` | +| `addons.gatewayAPI.enabled` | Enable the Gateway API | `false` | +| `addons.ingressNginx.enabled` | Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role). | `false` | +| `addons.ingressNginx.valuesOverride` | Custom values to override | `{}` | +| `addons.ingressNginx.hosts` | List of domain names that the parent cluster should route to this tenant cluster. | `[]` | +| `addons.gpuOperator.enabled` | Enable the GPU-operator | `false` | +| `addons.gpuOperator.valuesOverride` | Custom values to override | `{}` | +| `addons.fluxcd.enabled` | Enable FluxCD | `false` | +| `addons.fluxcd.valuesOverride` | Custom values to override | `{}` | +| `addons.monitoringAgents.enabled` | Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage. | `false` | +| `addons.monitoringAgents.valuesOverride` | Custom values to override | `{}` | +| `addons.verticalPodAutoscaler.valuesOverride` | Custom values to override | `{}` | + +### Kubernetes Control Plane Configuration + +| Name | Description | Value | +| -------------------------------------------------- | ---------------------------------------------------------------------------- | ------- | +| `controlPlane.apiServer.resources` | Explicit CPU/memory resource requests and limits for the API server. | `{}` | +| `controlPlane.apiServer.resourcesPreset` | Use a common resources preset when `resources` is not set explicitly. | `small` | +| `controlPlane.controllerManager.resources` | Explicit CPU/memory resource requests and limits for the controller manager. | `{}` | +| `controlPlane.controllerManager.resourcesPreset` | Use a common resources preset when `resources` is not set explicitly. | `micro` | +| `controlPlane.scheduler.resources` | Explicit CPU/memory resource requests and limits for the scheduler. | `{}` | +| `controlPlane.scheduler.resourcesPreset` | Use a common resources preset when `resources` is not set explicitly. | `micro` | +| `controlPlane.konnectivity.server.resources` | Explicit CPU/memory resource requests and limits for the Konnectivity. | `{}` | +| `controlPlane.konnectivity.server.resourcesPreset` | Use a common resources preset when `resources` is not set explicitly. | `micro` | + +In production environments, it's recommended to set `resources` explicitly. +Example of `controlPlane.*.resources`: + +```yaml +resources: + limits: + cpu: 4000m + memory: 4Gi + requests: + cpu: 100m + memory: 512Mi ``` -# Series +Allowed values for `controlPlane.*.resourcesPreset` are `none`, `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. +This value is ignored if the corresponding `resources` value is set. -<!-- source: https://github.com/kubevirt/common-instancetypes/blob/main/README.md --> +## Resources Reference -. | U | O | CX | M | RT -----------------------------|-----|-----|------|-----|------ -*Has GPUs* | | | | | -*Hugepages* | | | ✓ | ✓ | ✓ -*Overcommitted Memory* | | ✓ | | | -*Dedicated CPU* | | | ✓ | | ✓ -*Burstable CPU performance* | ✓ | ✓ | | ✓ | -*Isolated emulator threads* | | | ✓ | | ✓ -*vNUMA* | | | ✓ | | ✓ -*vCPU-To-Memory Ratio* | 1:4 | 1:4 | 1:2 | 1:8 | 1:4 +### instanceType Resources +The following instanceType resources are provided by Cozystack: -## U Series +| Name | vCPUs | Memory | +|---------------|-------|--------| +| `cx1.2xlarge` | 8 | 16Gi | +| `cx1.4xlarge` | 16 | 32Gi | +| `cx1.8xlarge` | 32 | 64Gi | +| `cx1.large` | 2 | 4Gi | +| `cx1.medium` | 1 | 2Gi | +| `cx1.xlarge` | 4 | 8Gi | +| `gn1.2xlarge` | 8 | 32Gi | +| `gn1.4xlarge` | 16 | 64Gi | +| `gn1.8xlarge` | 32 | 128Gi | +| `gn1.xlarge` | 4 | 16Gi | +| `m1.2xlarge` | 8 | 64Gi | +| `m1.4xlarge` | 16 | 128Gi | +| `m1.8xlarge` | 32 | 256Gi | +| `m1.large` | 2 | 16Gi | +| `m1.xlarge` | 4 | 32Gi | +| `n1.2xlarge` | 16 | 32Gi | +| `n1.4xlarge` | 32 | 64Gi | +| `n1.8xlarge` | 64 | 128Gi | +| `n1.large` | 4 | 8Gi | +| `n1.medium` | 4 | 4Gi | +| `n1.xlarge` | 8 | 16Gi | +| `o1.2xlarge` | 8 | 32Gi | +| `o1.4xlarge` | 16 | 64Gi | +| `o1.8xlarge` | 32 | 128Gi | +| `o1.large` | 2 | 8Gi | +| `o1.medium` | 1 | 4Gi | +| `o1.micro` | 1 | 1Gi | +| `o1.nano` | 1 | 512Mi | +| `o1.small` | 1 | 2Gi | +| `o1.xlarge` | 4 | 16Gi | +| `rt1.2xlarge` | 8 | 32Gi | +| `rt1.4xlarge` | 16 | 64Gi | +| `rt1.8xlarge` | 32 | 128Gi | +| `rt1.large` | 2 | 8Gi | +| `rt1.medium` | 1 | 4Gi | +| `rt1.micro` | 1 | 1Gi | +| `rt1.small` | 1 | 2Gi | +| `rt1.xlarge` | 4 | 16Gi | +| `u1.2xlarge` | 8 | 32Gi | +| `u1.2xmedium` | 2 | 4Gi | +| `u1.4xlarge` | 16 | 64Gi | +| `u1.8xlarge` | 32 | 128Gi | +| `u1.large` | 2 | 8Gi | +| `u1.medium` | 1 | 4Gi | +| `u1.micro` | 1 | 1Gi | +| `u1.nano` | 1 | 512Mi | +| `u1.small` | 1 | 2Gi | +| `u1.xlarge` | 4 | 16Gi | + +### U Series: Universal The U Series is quite neutral and provides resources for general purpose applications. @@ -54,7 +204,7 @@ attitude towards workloads. VMs of instance types will share physical CPU cores on a time-slice basis with other VMs. -### U Series Characteristics +#### U Series Characteristics Specific characteristics of this series are: - *Burstable CPU performance* - The workload has a baseline compute @@ -63,14 +213,14 @@ Specific characteristics of this series are: - *vCPU-To-Memory Ratio (1:4)* - A vCPU-to-Memory ratio of 1:4, for less noise per node. -## O Series +### O Series: Overcommitted The O Series is based on the U Series, with the only difference being that memory is overcommitted. *O* is the abbreviation for "Overcommitted". -### UO Series Characteristics +#### O Series Characteristics Specific characteristics of this series are: - *Burstable CPU performance* - The workload has a baseline compute @@ -81,7 +231,7 @@ Specific characteristics of this series are: - *vCPU-To-Memory Ratio (1:4)* - A vCPU-to-Memory ratio of 1:4, for less noise per node. -## CX Series +### CX Series: Compute Exclusive The CX Series provides exclusive compute resources for compute intensive applications. @@ -95,7 +245,7 @@ the IO threading from cores dedicated to the workload. In addition, in this series, the NUMA topology of the used cores is provided to the VM. -### CX Series Characteristics +#### CX Series Characteristics Specific characteristics of this series are: - *Hugepages* - Hugepages are used in order to improve memory @@ -110,14 +260,14 @@ Specific characteristics of this series are: optimize guest sided cache utilization. - *vCPU-To-Memory Ratio (1:2)* - A vCPU-to-Memory ratio of 1:2. -## M Series +### M Series: Memory The M Series provides resources for memory intensive applications. *M* is the abbreviation of "Memory". -### M Series Characteristics +#### M Series Characteristics Specific characteristics of this series are: - *Hugepages* - Hugepages are used in order to improve memory @@ -128,7 +278,7 @@ Specific characteristics of this series are: - *vCPU-To-Memory Ratio (1:8)* - A vCPU-to-Memory ratio of 1:8, for much less noise per node. -## RT Series +### RT Series: RealTime The RT Series provides resources for realtime applications, like Oslat. @@ -137,7 +287,7 @@ The RT Series provides resources for realtime applications, like Oslat. This series of instance types requires nodes capable of running realtime applications. -### RT Series Characteristics +#### RT Series Characteristics Specific characteristics of this series are: - *Hugepages* - Hugepages are used in order to improve memory @@ -151,57 +301,3 @@ Specific characteristics of this series are: - *vCPU-To-Memory Ratio (1:4)* - A vCPU-to-Memory ratio of 1:4 starting from the medium size. -## Resources - -The following instancetype resources are provided by Cozystack: - -Name | vCPUs | Memory ------|-------|------- -cx1.2xlarge | 8 | 16Gi -cx1.4xlarge | 16 | 32Gi -cx1.8xlarge | 32 | 64Gi -cx1.large | 2 | 4Gi -cx1.medium | 1 | 2Gi -cx1.xlarge | 4 | 8Gi -gn1.2xlarge | 8 | 32Gi -gn1.4xlarge | 16 | 64Gi -gn1.8xlarge | 32 | 128Gi -gn1.xlarge | 4 | 16Gi -m1.2xlarge | 8 | 64Gi -m1.4xlarge | 16 | 128Gi -m1.8xlarge | 32 | 256Gi -m1.large | 2 | 16Gi -m1.xlarge | 4 | 32Gi -n1.2xlarge | 16 | 32Gi -n1.4xlarge | 32 | 64Gi -n1.8xlarge | 64 | 128Gi -n1.large | 4 | 8Gi -n1.medium | 4 | 4Gi -n1.xlarge | 8 | 16Gi -o1.2xlarge | 8 | 32Gi -o1.4xlarge | 16 | 64Gi -o1.8xlarge | 32 | 128Gi -o1.large | 2 | 8Gi -o1.medium | 1 | 4Gi -o1.micro | 1 | 1Gi -o1.nano | 1 | 512Mi -o1.small | 1 | 2Gi -o1.xlarge | 4 | 16Gi -rt1.2xlarge | 8 | 32Gi -rt1.4xlarge | 16 | 64Gi -rt1.8xlarge | 32 | 128Gi -rt1.large | 2 | 8Gi -rt1.medium | 1 | 4Gi -rt1.micro | 1 | 1Gi -rt1.small | 1 | 2Gi -rt1.xlarge | 4 | 16Gi -u1.2xlarge | 8 | 32Gi -u1.2xmedium | 2 | 4Gi -u1.4xlarge | 16 | 64Gi -u1.8xlarge | 32 | 128Gi -u1.large | 2 | 8Gi -u1.medium | 1 | 4Gi -u1.micro | 1 | 1Gi -u1.nano | 1 | 512Mi -u1.small | 1 | 2Gi -u1.xlarge | 4 | 16Gi diff --git a/packages/apps/kubernetes/images/cluster-autoscaler.tag b/packages/apps/kubernetes/images/cluster-autoscaler.tag index 79b8f1fe..f14e64e5 100644 --- a/packages/apps/kubernetes/images/cluster-autoscaler.tag +++ b/packages/apps/kubernetes/images/cluster-autoscaler.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/cluster-autoscaler:0.18.0@sha256:85371c6aabf5a7fea2214556deac930c600e362f92673464fe2443784e2869c3 +ghcr.io/cozystack/cozystack/cluster-autoscaler:0.20.1@sha256:720148128917fa10f860a8b7e74f9428de72481c466c880c5ad894e1f0026d43 diff --git a/packages/apps/kubernetes/images/cluster-autoscaler/Dockerfile b/packages/apps/kubernetes/images/cluster-autoscaler/Dockerfile index 17a5e501..7f9ff896 100644 --- a/packages/apps/kubernetes/images/cluster-autoscaler/Dockerfile +++ b/packages/apps/kubernetes/images/cluster-autoscaler/Dockerfile @@ -1,7 +1,14 @@ # Source: https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/cluster-autoscaler/Dockerfile.amd64 ARG builder_image=docker.io/library/golang:1.23.4 -ARG BASEIMAGE=gcr.io/distroless/static:nonroot-amd64 +ARG BASEIMAGE=gcr.io/distroless/static:nonroot-${TARGETARCH} + FROM ${builder_image} AS builder + +ARG TARGETOS +ARG TARGETARCH +ENV GOOS=$TARGETOS +ENV GOARCH=$TARGETARCH + RUN git clone https://github.com/kubernetes/autoscaler /src/autoscaler \ && cd /src/autoscaler/cluster-autoscaler \ && git checkout cluster-autoscaler-1.32.0 @@ -14,6 +21,8 @@ RUN make build FROM $BASEIMAGE LABEL maintainer="Marcin Wielgus <mwielgus@google.com>" -COPY --from=builder /src/autoscaler/cluster-autoscaler/cluster-autoscaler-amd64 /cluster-autoscaler +ARG TARGETARCH + +COPY --from=builder /src/autoscaler/cluster-autoscaler/cluster-autoscaler-${TARGETARCH} /cluster-autoscaler WORKDIR / CMD ["/cluster-autoscaler"] diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag b/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag index 3da7f1c6..1ada8d04 100644 --- a/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag +++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.18.0@sha256:795d8e1ef4b2b0df2aa1e09d96cd13476ebb545b4bf4b5779b7547a70ef64cf9 +ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.20.1@sha256:1b48a4725a33ccb48604bb2e1be3171271e7daac2726d3119228212d8a9da5bb diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile b/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile index 97760bd7..0e2c3a2f 100644 --- a/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile +++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile @@ -1,5 +1,10 @@ # Source: https://github.com/kubevirt/cloud-provider-kubevirt/blob/main/build/images/kubevirt-cloud-controller-manager/Dockerfile -FROM --platform=linux/amd64 golang:1.20.6 AS builder +FROM golang:1.20.6 AS builder + +ARG TARGETOS +ARG TARGETARCH +ENV GOOS=$TARGETOS +ENV GOARCH=$TARGETARCH RUN git clone https://github.com/kubevirt/cloud-provider-kubevirt /go/src/kubevirt.io/cloud-provider-kubevirt \ && cd /go/src/kubevirt.io/cloud-provider-kubevirt \ @@ -14,7 +19,7 @@ RUN go get 'k8s.io/endpointslice/util@v0.28' 'k8s.io/apiserver@v0.28' RUN go mod tidy RUN go mod vendor -RUN CGO_ENABLED=0 GOOS=linux go build -mod=vendor -ldflags="-s -w" -o bin/kubevirt-cloud-controller-manager ./cmd/kubevirt-cloud-controller-manager +RUN CGO_ENABLED=0 go build -mod=vendor -ldflags="-s -w" -o bin/kubevirt-cloud-controller-manager ./cmd/kubevirt-cloud-controller-manager FROM registry.access.redhat.com/ubi9/ubi-micro COPY --from=builder /go/src/kubevirt.io/cloud-provider-kubevirt/bin/kubevirt-cloud-controller-manager /bin/kubevirt-cloud-controller-manager diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index a06f4311..21e11de9 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.18.0@sha256:6f9091c3e7e4951c5e43fdafd505705fcc9f1ead290ee3ae42e97e9ec2b87b20 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.20.1@sha256:fb6d3ce9d6d948285a6d399c852e15259d6922162ec7c44177d2274243f59d1f diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile b/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile index b53c7b3d..27dda789 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile @@ -5,6 +5,11 @@ RUN git clone https://github.com/kubevirt/csi-driver /src/kubevirt-csi-driver \ && cd /src/kubevirt-csi-driver \ && git checkout 35836e0c8b68d9916d29a838ea60cdd3fc6199cf +ARG TARGETOS +ARG TARGETARCH +ENV GOOS=$TARGETOS +ENV GOARCH=$TARGETARCH + WORKDIR /src/kubevirt-csi-driver RUN make build diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk.tag b/packages/apps/kubernetes/images/ubuntu-container-disk.tag index 5c36c7ea..c49750c8 100644 --- a/packages/apps/kubernetes/images/ubuntu-container-disk.tag +++ b/packages/apps/kubernetes/images/ubuntu-container-disk.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.30.1@sha256:07392e7a87a3d4ef1c86c1b146e6c5de5c2b524aed5a53bf48870dc8a296f99a +ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.32@sha256:184b81529ae72684279799b12f436cc7a511d8ff5bd1e9a30478799c7707c625 diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk/Dockerfile b/packages/apps/kubernetes/images/ubuntu-container-disk/Dockerfile index eb08ef10..f5a7d54d 100644 --- a/packages/apps/kubernetes/images/ubuntu-container-disk/Dockerfile +++ b/packages/apps/kubernetes/images/ubuntu-container-disk/Dockerfile @@ -1,19 +1,26 @@ -FROM ubuntu:22.04 as guestfish +# TODO: Here we use ubuntu:22.04, as guestfish has some network issues running in ubuntu:24.04 +FROM ubuntu:22.04 AS guestfish ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get -y install \ libguestfs-tools \ linux-image-generic \ + wget \ make \ - bash-completion \ - && apt-get clean + bash-completion WORKDIR /build -FROM guestfish as builder +FROM guestfish AS builder -RUN wget -O image.img https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img +ARG TARGETOS +ARG TARGETARCH + +# noble is a code name for the Ubuntu 24.04 LTS release +RUN wget -O image.img https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-${TARGETARCH}.img --show-progress --output-file /dev/stdout --progress=dot:giga 2>/dev/null + +ARG KUBERNETES_VERSION RUN qemu-img resize image.img 5G \ && eval "$(guestfish --listen --network)" \ @@ -24,19 +31,21 @@ RUN qemu-img resize image.img 5G \ && guestfish --remote command "resize2fs /dev/sda1" \ # docker repo && guestfish --remote sh "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg" \ - && guestfish --remote sh 'echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list' \ + && guestfish --remote sh 'echo "deb [signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list' \ # kubernetes repo - && guestfish --remote sh "curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg" \ - && guestfish --remote sh "echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list" \ + && guestfish --remote sh "curl -fsSL https://pkgs.k8s.io/core:/stable:/${KUBERNETES_VERSION}/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg" \ + && guestfish --remote sh "echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${KUBERNETES_VERSION}/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list" \ + && guestfish --remote command "apt-get check -q" \ # install containerd - && guestfish --remote command "apt-get update -y" \ - && guestfish --remote command "apt-get install -y containerd.io" \ + && guestfish --remote command "apt-get update -q" \ + && guestfish --remote command "apt-get install -yq containerd.io" \ # configure containerd && guestfish --remote command "mkdir -p /etc/containerd" \ && guestfish --remote sh "containerd config default | tee /etc/containerd/config.toml" \ && guestfish --remote command "sed -i '/SystemdCgroup/ s/=.*/= true/' /etc/containerd/config.toml" \ + && guestfish --remote command "containerd config dump >/dev/null" \ # install kubernetes - && guestfish --remote command "apt-get install -y kubelet kubeadm" \ + && guestfish --remote command "apt-get install -yq kubelet kubeadm" \ # clean apt cache && guestfish --remote sh 'apt-get clean && rm -rf /var/lib/apt/lists/*' \ # write system configuration diff --git a/packages/apps/kubernetes/templates/_resources.tpl b/packages/apps/kubernetes/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/kubernetes/templates/_resources.tpl +++ b/packages/apps/kubernetes/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml index a208bc6e..1c688419 100644 --- a/packages/apps/kubernetes/templates/cluster.yaml +++ b/packages/apps/kubernetes/templates/cluster.yaml @@ -39,6 +39,13 @@ spec: sockets: 1 {{- end }} devices: + {{- if .group.gpus }} + gpus: + {{- range $i, $gpu := .group.gpus }} + - name: gpu{{ add $i 1 }} + deviceName: {{ $gpu.name }} + {{- end }} + {{- end }} disks: - name: system disk: @@ -103,22 +110,22 @@ metadata: kamaji.clastix.io/kubeconfig-secret-key: "super-admin.svc" spec: apiServer: - {{- if .Values.kamajiControlPlane.apiServer.resources }} - resources: {{- toYaml .Values.kamajiControlPlane.apiServer.resources | nindent 6 }} - {{- else if ne .Values.kamajiControlPlane.apiServer.resourcesPreset "none" }} - resources: {{- include "resources.preset" (dict "type" .Values.kamajiControlPlane.apiServer.resourcesPreset "Release" .Release) | nindent 6 }} + {{- if .Values.controlPlane.apiServer.resources }} + resources: {{- toYaml .Values.controlPlane.apiServer.resources | nindent 6 }} + {{- else if ne .Values.controlPlane.apiServer.resourcesPreset "none" }} + resources: {{- include "resources.preset" (dict "type" .Values.controlPlane.apiServer.resourcesPreset "Release" .Release) | nindent 6 }} {{- end }} controllerManager: - {{- if .Values.kamajiControlPlane.controllerManager.resources }} - resources: {{- toYaml .Values.kamajiControlPlane.controllerManager.resources | nindent 6 }} - {{- else if ne .Values.kamajiControlPlane.controllerManager.resourcesPreset "none" }} - resources: {{- include "resources.preset" (dict "type" .Values.kamajiControlPlane.controllerManager.resourcesPreset "Release" .Release) | nindent 6 }} + {{- if .Values.controlPlane.controllerManager.resources }} + resources: {{- toYaml .Values.controlPlane.controllerManager.resources | nindent 6 }} + {{- else if ne .Values.controlPlane.controllerManager.resourcesPreset "none" }} + resources: {{- include "resources.preset" (dict "type" .Values.controlPlane.controllerManager.resourcesPreset "Release" .Release) | nindent 6 }} {{- end }} scheduler: - {{- if .Values.kamajiControlPlane.scheduler.resources }} - resources: {{- toYaml .Values.kamajiControlPlane.scheduler.resources | nindent 6 }} - {{- else if ne .Values.kamajiControlPlane.scheduler.resourcesPreset "none" }} - resources: {{- include "resources.preset" (dict "type" .Values.kamajiControlPlane.scheduler.resourcesPreset "Release" .Release) | nindent 6 }} + {{- if .Values.controlPlane.scheduler.resources }} + resources: {{- toYaml .Values.controlPlane.scheduler.resources | nindent 6 }} + {{- else if ne .Values.controlPlane.scheduler.resourcesPreset "none" }} + resources: {{- include "resources.preset" (dict "type" .Values.controlPlane.scheduler.resourcesPreset "Release" .Release) | nindent 6 }} {{- end }} dataStoreName: "{{ $etcd }}" addons: @@ -128,10 +135,10 @@ spec: konnectivity: server: port: 8132 - {{- if .Values.kamajiControlPlane.addons.konnectivity.server.resources }} - resources: {{- toYaml .Values.kamajiControlPlane.addons.konnectivity.server.resources | nindent 10 }} - {{- else if ne .Values.kamajiControlPlane.addons.konnectivity.server.resourcesPreset "none" }} - resources: {{- include "resources.preset" (dict "type" .Values.kamajiControlPlane.addons.konnectivity.server.resourcesPreset "Release" .Release) | nindent 10 }} + {{- if .Values.controlPlane.konnectivity.server.resources }} + resources: {{- toYaml .Values.controlPlane.konnectivity.server.resources | nindent 10 }} + {{- else if ne .Values.controlPlane.konnectivity.server.resourcesPreset "none" }} + resources: {{- include "resources.preset" (dict "type" .Values.controlPlane.konnectivity.server.resourcesPreset "Release" .Release) | nindent 10 }} {{- end }} kubelet: cgroupfs: systemd @@ -143,14 +150,14 @@ spec: ingress: extraAnnotations: nginx.ingress.kubernetes.io/ssl-passthrough: "true" - hostname: {{ .Values.host | default (printf "%s.%s" .Release.Name $host) }} + hostname: {{ .Values.host | default (printf "%s.%s" .Release.Name $host) }}:443 className: "{{ $ingress }}" deployment: podAdditionalMetadata: labels: policy.cozystack.io/allow-to-etcd: "true" replicas: 2 - version: 1.30.1 + version: {{ $.Chart.AppVersion }} --- apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor @@ -276,7 +283,7 @@ spec: kind: KubevirtMachineTemplate name: {{ $.Release.Name }}-{{ $groupName }}-{{ $kubevirtmachinetemplateHash }} namespace: {{ $.Release.Namespace }} - version: v1.30.1 + version: v{{ $.Chart.AppVersion }} --- apiVersion: cluster.x-k8s.io/v1beta1 kind: MachineHealthCheck diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml index 8ee5dc82..21b7ba4d 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml @@ -4,7 +4,7 @@ metadata: name: {{ .Release.Name }}-cert-manager-crds labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: cert-manager-crds @@ -16,6 +16,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml index 8a7213a9..3a6e4939 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml @@ -5,7 +5,7 @@ metadata: name: {{ .Release.Name }}-cert-manager labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: cert-manager @@ -17,6 +17,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -30,11 +31,9 @@ spec: upgrade: remediation: retries: -1 - {{- if .Values.addons.certManager.valuesOverride }} - valuesFrom: - - kind: Secret - name: {{ .Release.Name }}-cert-manager-values-override - valuesKey: values + {{- with .Values.addons.certManager.valuesOverride }} + values: + {{- toYaml . | nindent 4 }} {{- end }} dependsOn: @@ -47,13 +46,3 @@ spec: - name: {{ .Release.Name }}-cert-manager-crds namespace: {{ .Release.Namespace }} {{- end }} -{{- if .Values.addons.certManager.valuesOverride }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-cert-manager-values-override -stringData: - values: | - {{- toYaml .Values.addons.certManager.valuesOverride | nindent 4 }} -{{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml index cf6bbe12..7e8c7480 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml @@ -1,10 +1,25 @@ +{{- define "cozystack.defaultCiliumValues" -}} +cilium: + k8sServiceHost: {{ .Release.Name }}.{{ .Release.Namespace }}.svc + k8sServicePort: 6443 + routingMode: tunnel + enableIPv4Masquerade: true + ipv4NativeRoutingCIDR: "" + {{- if $.Values.addons.gatewayAPI.enabled }} + gatewayAPI: + enabled: true + envoy: + enabled: true + {{- end }} +{{- end }} + apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: {{ .Release.Name }}-cilium labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: cilium @@ -16,6 +31,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -30,14 +46,13 @@ spec: remediation: retries: -1 values: - cilium: - k8sServiceHost: {{ .Release.Name }}.{{ .Release.Namespace }}.svc - k8sServicePort: 6443 - routingMode: tunnel - enableIPv4Masquerade: true - ipv4NativeRoutingCIDR: "" + {{- toYaml (deepCopy .Values.addons.cilium.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultCiliumValues" .))) | nindent 4 }} dependsOn: {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} - name: {{ .Release.Name }} namespace: {{ .Release.Namespace }} {{- end }} + {{- if $.Values.addons.gatewayAPI.enabled }} + - name: {{ .Release.Name }}-gateway-api-crds + namespace: {{ .Release.Namespace }} + {{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/csi.yaml b/packages/apps/kubernetes/templates/helmreleases/csi.yaml index 2fe33509..8bbb1b9d 100644 --- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml @@ -4,7 +4,7 @@ metadata: name: {{ .Release.Name }}-csi labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: csi @@ -16,6 +16,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/delete.yaml b/packages/apps/kubernetes/templates/helmreleases/delete.yaml index 35cacedb..5b32588e 100644 --- a/packages/apps/kubernetes/templates/helmreleases/delete.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/delete.yaml @@ -20,7 +20,7 @@ spec: effect: "NoSchedule" containers: - name: kubectl - image: docker.io/clastix/kubectl:v1.30.1 + image: docker.io/clastix/kubectl:v1.32 command: - /bin/sh - -c @@ -30,6 +30,7 @@ spec: patch helmrelease {{ .Release.Name }}-cilium + {{ .Release.Name }}-gateway-api-crds {{ .Release.Name }}-csi {{ .Release.Name }}-cert-manager {{ .Release.Name }}-cert-manager-crds @@ -38,6 +39,7 @@ spec: {{ .Release.Name }}-ingress-nginx {{ .Release.Name }}-fluxcd-operator {{ .Release.Name }}-fluxcd + {{ .Release.Name }}-gpu-operator -p '{"spec": {"suspend": true}}' --type=merge --field-manager=flux-client-side-apply || true --- @@ -76,6 +78,7 @@ rules: - {{ .Release.Name }}-ingress-nginx - {{ .Release.Name }}-fluxcd-operator - {{ .Release.Name }}-fluxcd + - {{ .Release.Name }}-gpu-operator --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml index c11629b9..944ce8cf 100644 --- a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml @@ -5,7 +5,7 @@ metadata: name: {{ .Release.Name }}-fluxcd-operator labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: fluxcd-operator @@ -17,6 +17,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -49,7 +50,7 @@ metadata: name: {{ .Release.Name }}-fluxcd labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: fluxcd @@ -61,6 +62,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-kubeconfig @@ -73,11 +75,9 @@ spec: upgrade: remediation: retries: -1 - {{- if .Values.addons.fluxcd.valuesOverride }} - valuesFrom: - - kind: Secret - name: {{ .Release.Name }}-fluxcd-values-override - valuesKey: values + {{- with .Values.addons.fluxcd.valuesOverride }} + values: + {{- toYaml . | nindent 4 }} {{- end }} dependsOn: {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} @@ -89,14 +89,3 @@ spec: - name: {{ .Release.Name }}-fluxcd-operator namespace: {{ .Release.Namespace }} {{- end }} - -{{- if .Values.addons.fluxcd.valuesOverride }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-fluxcd-values-override -stringData: - values: | - {{- toYaml .Values.addons.fluxcd.valuesOverride | nindent 4 }} -{{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml new file mode 100644 index 00000000..1cac6dd9 --- /dev/null +++ b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml @@ -0,0 +1,38 @@ +{{- if $.Values.addons.gatewayAPI.enabled }} +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-gateway-api-crds + labels: + cozystack.io/repository: system + cozystack.io/target-cluster-name: {{ .Release.Name }} +spec: + interval: 5m + releaseName: gateway-api-crds + chart: + spec: + chart: cozy-gateway-api-crds + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + kubeConfig: + secretRef: + name: {{ .Release.Name }}-admin-kubeconfig + key: super-admin.svc + targetNamespace: kube-system + storageNamespace: kube-system + install: + createNamespace: false + remediation: + retries: -1 + upgrade: + remediation: + retries: -1 + dependsOn: + {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} + - name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + {{- end }} +{{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml new file mode 100644 index 00000000..861c3657 --- /dev/null +++ b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml @@ -0,0 +1,46 @@ +{{- if .Values.addons.gpuOperator.enabled }} +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-gpu-operator + labels: + cozystack.io/repository: system + cozystack.io/target-cluster-name: {{ .Release.Name }} +spec: + interval: 5m + releaseName: gpu-operator + chart: + spec: + chart: cozy-gpu-operator + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' + kubeConfig: + secretRef: + name: {{ .Release.Name }}-admin-kubeconfig + key: super-admin.svc + targetNamespace: cozy-gpu-operator + storageNamespace: cozy-gpu-operator + install: + createNamespace: true + remediation: + retries: -1 + upgrade: + remediation: + retries: -1 + {{- with .Values.addons.gpuOperator.valuesOverride }} + values: + {{- toYaml . | nindent 4 }} + {{- end }} + + dependsOn: + {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} + - name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + {{- end }} + - name: {{ .Release.Name }}-cilium + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml index 8daaf01f..68ad8e63 100644 --- a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml @@ -1,3 +1,20 @@ +{{- define "cozystack.defaultIngressValues" -}} +ingress-nginx: + fullnameOverride: ingress-nginx + controller: + kind: DaemonSet + hostNetwork: true + service: + enabled: false + {{- if not .Values.addons.certManager.enabled }} + admissionWebhooks: + certManager: + enabled: false + {{- end }} + nodeSelector: + node-role.kubernetes.io/ingress-nginx: "" +{{- end }} + {{- if .Values.addons.ingressNginx.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease @@ -5,7 +22,7 @@ metadata: name: {{ .Release.Name }}-ingress-nginx labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: ingress-nginx @@ -17,6 +34,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -31,21 +49,7 @@ spec: remediation: retries: -1 values: - ingress-nginx: - fullnameOverride: ingress-nginx - controller: - kind: DaemonSet - hostNetwork: true - service: - enabled: false - nodeSelector: - node-role.kubernetes.io/ingress-nginx: "" - {{- if .Values.addons.ingressNginx.valuesOverride }} - valuesFrom: - - kind: Secret - name: {{ .Release.Name }}-ingress-nginx-values-override - valuesKey: values - {{- end }} + {{- toYaml (deepCopy .Values.addons.ingressNginx.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultIngressValues" .))) | nindent 4 }} dependsOn: {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} - name: {{ .Release.Name }} @@ -54,14 +58,3 @@ spec: - name: {{ .Release.Name }}-cilium namespace: {{ .Release.Namespace }} {{- end }} - -{{- if .Values.addons.ingressNginx.valuesOverride }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-ingress-nginx-values-override -stringData: - values: | - {{- toYaml .Values.addons.ingressNginx.valuesOverride | nindent 4 }} -{{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index eb19f23b..f046ff0d 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -7,7 +7,7 @@ metadata: name: {{ .Release.Name }}-monitoring-agents labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: cozy-monitoring-agents @@ -19,6 +19,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml index 89634565..336c198b 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml @@ -5,7 +5,7 @@ metadata: name: {{ .Release.Name }}-vertical-pod-autoscaler-crds labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: vertical-pod-autoscaler-crds @@ -17,6 +17,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index d5e17079..a4b6c431 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -1,5 +1,28 @@ +{{- define "cozystack.defaultVPAValues" -}} {{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} {{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }} +vertical-pod-autoscaler: + recommender: + extraArgs: + container-name-label: container + container-namespace-label: namespace + container-pod-name-label: pod + storage: prometheus + memory-saver: true + pod-label-prefix: label_ + metric-for-pod-labels: kube_pod_labels{job="kube-state-metrics", tenant="{{ .Release.Namespace }}", cluster="{{ .Release.Name }}"}[8d] + pod-name-label: pod + pod-namespace-label: namespace + prometheus-address: http://vmselect-shortterm.{{ $targetTenant }}.svc.cozy.local:8481/select/0/prometheus/ + prometheus-cadvisor-job-name: cadvisor + resources: + limits: + memory: 1600Mi + requests: + cpu: 100m + memory: 1600Mi +{{- end }} + {{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease @@ -7,7 +30,7 @@ metadata: name: {{ .Release.Name }}-vertical-pod-autoscaler labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: vertical-pod-autoscaler @@ -19,6 +42,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -33,32 +57,7 @@ spec: remediation: retries: -1 values: - vertical-pod-autoscaler: - recommender: - extraArgs: - container-name-label: container - container-namespace-label: namespace - container-pod-name-label: pod - storage: prometheus - memory-saver: true - pod-label-prefix: label_ - metric-for-pod-labels: kube_pod_labels{job="kube-state-metrics", tenant="{{ .Release.Namespace }}", cluster="{{ .Release.Name }}"}[8d] - pod-name-label: pod - pod-namespace-label: namespace - prometheus-address: http://vmselect-shortterm.{{ $targetTenant }}.svc.cozy.local:8481/select/0/prometheus/ - prometheus-cadvisor-job-name: cadvisor - resources: - limits: - memory: 1600Mi - requests: - cpu: 100m - memory: 1600Mi - {{- if .Values.addons.verticalPodAutoscaler.valuesOverride }} - valuesFrom: - - kind: Secret - name: {{ .Release.Name }}-vertical-pod-autoscaler-values-override - valuesKey: values - {{- end }} + {{- toYaml (deepCopy .Values.addons.verticalPodAutoscaler.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultVPAValues" .))) | nindent 4 }} dependsOn: {{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }} - name: {{ .Release.Name }} diff --git a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml index de19c968..91445c45 100644 --- a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml @@ -5,7 +5,7 @@ metadata: name: {{ .Release.Name }}-cozy-victoria-metrics-operator labels: cozystack.io/repository: system - coztstack.io/target-cluster-name: {{ .Release.Name }} + cozystack.io/target-cluster-name: {{ .Release.Name }} spec: interval: 5m releaseName: cozy-victoria-metrics-operator @@ -17,6 +17,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/values.schema.json b/packages/apps/kubernetes/values.schema.json index ed0de279..b96fadf0 100644 --- a/packages/apps/kubernetes/values.schema.json +++ b/packages/apps/kubernetes/values.schema.json @@ -1,97 +1,247 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "The hostname used to access the Kubernetes cluster externally (defaults to using the cluster name as a subdomain for the tenant host).", - "default": "" + "title": "Chart Values", + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "Hostname used to access the Kubernetes cluster externally. Defaults to `<cluster-name>.<tenant-host>` when empty.", + "default": "" + }, + "controlPlane": { + "type": "object", + "properties": { + "replicas": { + "type": "number", + "description": "Number of replicas for Kubernetes control-plane components.", + "default": 2 }, - "controlPlane": { - "type": "object", - "properties": { - "replicas": { - "type": "number", - "description": "Number of replicas for Kubernetes contorl-plane components", - "default": 2 - } + "apiServer": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "description": "Explicit CPU/memory resource requests and limits for the API server.", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Use a common resources preset when `resources` is not set explicitly.", + "default": "small", + "enum": [ + "none", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] } + } }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store user data", - "default": "replicated" - }, - "addons": { - "type": "object", - "properties": { - "certManager": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enables the cert-manager", - "default": false - }, - "valuesOverride": { - "type": "object", - "description": "Custom values to override", - "default": {} - } - } - }, - "ingressNginx": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable Ingress-NGINX controller (expect nodes with 'ingress-nginx' role)", - "default": false - }, - "valuesOverride": { - "type": "object", - "description": "Custom values to override", - "default": {} - }, - "hosts": { - "type": "array", - "description": "List of domain names that should be passed through to the cluster by upper cluster", - "default": [], - "items": {} - } - } - }, - "fluxcd": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enables Flux CD", - "default": false - }, - "valuesOverride": { - "type": "object", - "description": "Custom values to override", - "default": {} - } - } - }, - "monitoringAgents": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enables MonitoringAgents (fluentbit, vmagents for sending logs and metrics to storage) if tenant monitoring enabled, send to tenant storage, else to root storage", - "default": false - }, - "valuesOverride": { - "type": "object", - "description": "Custom values to override", - "default": {} - } - } - } + "controllerManager": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "description": "Explicit CPU/memory resource requests and limits for the controller manager.", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Use a common resources preset when `resources` is not set explicitly.", + "default": "micro", + "enum": [ + "none", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] } + } + }, + "scheduler": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "description": "Explicit CPU/memory resource requests and limits for the scheduler.", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Use a common resources preset when `resources` is not set explicitly.", + "default": "micro", + "enum": [ + "none", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + } + } + }, + "konnectivity": { + "type": "object", + "properties": { + "server": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "description": "Explicit CPU/memory resource requests and limits for the Konnectivity.", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Use a common resources preset when `resources` is not set explicitly.", + "default": "micro", + "enum": [ + "none", + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + } + } + } + } } + } + }, + "storageClass": { + "type": "string", + "description": "StorageClass used to store user data.", + "default": "replicated" + }, + "addons": { + "type": "object", + "properties": { + "certManager": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable cert-manager, which automatically creates and manages SSL/TLS certificates.", + "default": false + }, + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + } + } + }, + "cilium": { + "type": "object", + "properties": { + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + } + } + }, + "gatewayAPI": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable the Gateway API", + "default": false + } + } + }, + "ingressNginx": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role).", + "default": false + }, + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + }, + "hosts": { + "type": "array", + "description": "List of domain names that the parent cluster should route to this tenant cluster.", + "default": [], + "items": {} + } + } + }, + "gpuOperator": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable the GPU-operator", + "default": false + }, + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + } + } + }, + "fluxcd": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable FluxCD", + "default": false + }, + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + } + } + }, + "monitoringAgents": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage.", + "default": false + }, + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + } + } + }, + "verticalPodAutoscaler": { + "type": "object", + "properties": { + "valuesOverride": { + "type": "object", + "description": "Custom values to override", + "default": {} + } + } + } + } } + } } diff --git a/packages/apps/kubernetes/values.yaml b/packages/apps/kubernetes/values.yaml index 9fb60221..d0d7f36d 100644 --- a/packages/apps/kubernetes/values.yaml +++ b/packages/apps/kubernetes/values.yaml @@ -1,12 +1,10 @@ -## @section Common parameters +## @section Common Parameters -## @param host The hostname used to access the Kubernetes cluster externally (defaults to using the cluster name as a subdomain for the tenant host). -## @param controlPlane.replicas Number of replicas for Kubernetes contorl-plane components -## @param storageClass StorageClass used to store user data +## @param host Hostname used to access the Kubernetes cluster externally. Defaults to `<cluster-name>.<tenant-host>` when empty. +## @param controlPlane.replicas Number of replicas for Kubernetes control-plane components. +## @param storageClass StorageClass used to store user data. ## host: "" -controlPlane: - replicas: 2 storageClass: replicated ## @param nodeGroups [object] nodeGroups configuration @@ -24,6 +22,14 @@ nodeGroups: cpu: "" memory: "" + ## List of GPUs to attach (WARN: NVIDIA driver requires at least 4 GiB of RAM) + ## e.g: + ## instanceType: "u1.xlarge" + ## gpus: + ## - name: nvidia.com/AD102GL_L40S + gpus: [] + + ## @section Cluster Addons ## addons: @@ -31,19 +37,31 @@ addons: ## Cert-manager: automatically creates and manages SSL/TLS certificate ## certManager: - ## @param addons.certManager.enabled Enables the cert-manager + ## @param addons.certManager.enabled Enable cert-manager, which automatically creates and manages SSL/TLS certificates. ## @param addons.certManager.valuesOverride Custom values to override enabled: false valuesOverride: {} + ## Cilium CNI plugin + ## + cilium: + ## @param addons.cilium.valuesOverride Custom values to override + valuesOverride: {} + + ## Gateway API + ## + gatewayAPI: + ## @param addons.gatewayAPI.enabled Enable the Gateway API + enabled: false + ## Ingress-NGINX Controller ## ingressNginx: - ## @param addons.ingressNginx.enabled Enable Ingress-NGINX controller (expect nodes with 'ingress-nginx' role) + ## @param addons.ingressNginx.enabled Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role). ## @param addons.ingressNginx.valuesOverride Custom values to override ## enabled: false - ## @param addons.ingressNginx.hosts List of domain names that should be passed through to the cluster by upper cluster + ## @param addons.ingressNginx.hosts List of domain names that the parent cluster should route to this tenant cluster. ## e.g: ## hosts: ## - example.org @@ -52,10 +70,18 @@ addons: hosts: [] valuesOverride: {} + ## GPU-operator: NVIDIA GPU Operator + ## + gpuOperator: + ## @param addons.gpuOperator.enabled Enable the GPU-operator + ## @param addons.gpuOperator.valuesOverride Custom values to override + enabled: false + valuesOverride: {} + ## Flux CD ## fluxcd: - ## @param addons.fluxcd.enabled Enables Flux CD + ## @param addons.fluxcd.enabled Enable FluxCD ## @param addons.fluxcd.valuesOverride Custom values to override ## enabled: false @@ -64,7 +90,7 @@ addons: ## MonitoringAgents ## monitoringAgents: - ## @param addons.monitoringAgents.enabled Enables MonitoringAgents (fluentbit, vmagents for sending logs and metrics to storage) if tenant monitoring enabled, send to tenant storage, else to root storage + ## @param addons.monitoringAgents.enabled Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage. ## @param addons.monitoringAgents.valuesOverride Custom values to override ## enabled: false @@ -77,62 +103,42 @@ addons: ## valuesOverride: {} -## @section Kamaji control plane +## @section Kubernetes Control Plane Configuration ## -kamajiControlPlane: + +controlPlane: + replicas: 2 + apiServer: - ## @param kamajiControlPlane.apiServer.resources Resources - resources: {} - # resources: - # limits: - # cpu: 4000m - # memory: 4Gi - # requests: - # cpu: 100m - # memory: 512Mi - - ## @param kamajiControlPlane.apiServer.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). + ## @param controlPlane.apiServer.resources Explicit CPU/memory resource requests and limits for the API server. + ## @param controlPlane.apiServer.resourcesPreset Use a common resources preset when `resources` is not set explicitly. + ## e.g: + ## resources: + ## limits: + ## cpu: 4000m + ## memory: 4Gi + ## requests: + ## cpu: 100m + ## memory: 512Mi + ## resourcesPreset: "small" + resources: {} controllerManager: - ## @param kamajiControlPlane.controllerManager.resources Resources - resources: {} - # resources: - # limits: - # cpu: 4000m - # memory: 4Gi - # requests: - # cpu: 100m - # memory: 512Mi - - ## @param kamajiControlPlane.controllerManager.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). + ## @param controlPlane.controllerManager.resources Explicit CPU/memory resource requests and limits for the controller manager. + ## @param controlPlane.controllerManager.resourcesPreset Use a common resources preset when `resources` is not set explicitly. resourcesPreset: "micro" + resources: {} + scheduler: - ## @param kamajiControlPlane.scheduler.resources Resources - resources: {} - # resources: - # limits: - # cpu: 4000m - # memory: 4Gi - # requests: - # cpu: 100m - # memory: 512Mi - - ## @param kamajiControlPlane.scheduler.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). + ## @param controlPlane.scheduler.resources Explicit CPU/memory resource requests and limits for the scheduler. + ## @param controlPlane.scheduler.resourcesPreset Use a common resources preset when `resources` is not set explicitly. resourcesPreset: "micro" - addons: - konnectivity: - server: - ## @param kamajiControlPlane.addons.konnectivity.server.resources Resources - resources: {} - # resources: - # limits: - # cpu: 4000m - # memory: 4Gi - # requests: - # cpu: 100m - # memory: 512Mi - - ## @param kamajiControlPlane.addons.konnectivity.server.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). - resourcesPreset: "micro" - \ No newline at end of file + resources: {} + + konnectivity: + server: + ## @param controlPlane.konnectivity.server.resources Explicit CPU/memory resource requests and limits for the Konnectivity. + ## @param controlPlane.konnectivity.server.resourcesPreset Use a common resources preset when `resources` is not set explicitly. + resourcesPreset: "micro" + resources: {} diff --git a/packages/apps/mysql/Chart.yaml b/packages/apps/mysql/Chart.yaml index d8d04d0c..f9dcb7c6 100644 --- a/packages/apps/mysql/Chart.yaml +++ b/packages/apps/mysql/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.6.0 +version: 0.7.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/mysql/Makefile b/packages/apps/mysql/Makefile index d32df5dd..8bc17337 100644 --- a/packages/apps/mysql/Makefile +++ b/packages/apps/mysql/Makefile @@ -7,8 +7,10 @@ generate: readme-generator -v values.yaml -s values.schema.json -r README.md image: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/mariadb-backup \ + docker buildx build images/mariadb-backup \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/mariadb-backup:$(call settag,$(MARIADB_BACKUP_TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/mariadb-backup:latest \ --cache-to type=inline \ diff --git a/packages/apps/mysql/images/mariadb-backup.tag b/packages/apps/mysql/images/mariadb-backup.tag index ad22d940..90a9bb59 100644 --- a/packages/apps/mysql/images/mariadb-backup.tag +++ b/packages/apps/mysql/images/mariadb-backup.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/mariadb-backup:0.6.0@sha256:cfd1c37d8ad24e10681d82d6e6ce8a641b4602c1b0ffa8516ae15b4958bb12d4 +ghcr.io/cozystack/cozystack/mariadb-backup:0.7.0@sha256:cfd1c37d8ad24e10681d82d6e6ce8a641b4602c1b0ffa8516ae15b4958bb12d4 diff --git a/packages/apps/mysql/templates/_resources.tpl b/packages/apps/mysql/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/mysql/templates/_resources.tpl +++ b/packages/apps/mysql/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/nats/Chart.yaml b/packages/apps/nats/Chart.yaml index 2bae5c73..38f429fb 100644 --- a/packages/apps/nats/Chart.yaml +++ b/packages/apps/nats/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.5.0 +version: 0.6.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/nats/templates/_resources.tpl b/packages/apps/nats/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/nats/templates/_resources.tpl +++ b/packages/apps/nats/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 019c7984..0041379a 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -33,7 +33,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system - version: '*' + version: '>= 0.0.0-0' interval: 1m0s timeout: 5m0s values: diff --git a/packages/apps/postgres/Chart.yaml b/packages/apps/postgres/Chart.yaml index 4dcda816..7c262043 100644 --- a/packages/apps/postgres/Chart.yaml +++ b/packages/apps/postgres/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.10.0 +version: 0.11.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/postgres/Makefile b/packages/apps/postgres/Makefile index 78639877..c0a894c0 100644 --- a/packages/apps/postgres/Makefile +++ b/packages/apps/postgres/Makefile @@ -7,8 +7,10 @@ generate: readme-generator -v values.yaml -s values.schema.json -r README.md image: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/postgres-backup \ + docker buildx build images/postgres-backup \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/postgres-backup:$(call settag,$(POSTGRES_BACKUP_TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/postgres-backup:latest \ --cache-to type=inline \ diff --git a/packages/apps/postgres/images/postgres-backup.tag b/packages/apps/postgres/images/postgres-backup.tag index 631a088b..e47315f2 100644 --- a/packages/apps/postgres/images/postgres-backup.tag +++ b/packages/apps/postgres/images/postgres-backup.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/postgres-backup:0.10.0@sha256:10179ed56457460d95cd5708db2a00130901255fa30c4dd76c65d2ef5622b61f +ghcr.io/cozystack/cozystack/postgres-backup:0.11.0@sha256:10179ed56457460d95cd5708db2a00130901255fa30c4dd76c65d2ef5622b61f diff --git a/packages/apps/postgres/templates/_resources.tpl b/packages/apps/postgres/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/postgres/templates/_resources.tpl +++ b/packages/apps/postgres/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/postgres/templates/backup-cronjob.yaml b/packages/apps/postgres/templates/backup-cronjob.yaml index 9775ca87..1998357a 100644 --- a/packages/apps/postgres/templates/backup-cronjob.yaml +++ b/packages/apps/postgres/templates/backup-cronjob.yaml @@ -13,9 +13,6 @@ spec: jobTemplate: spec: backoffLimit: 2 - template: - spec: - restartPolicy: OnFailure template: metadata: annotations: @@ -24,7 +21,7 @@ spec: spec: imagePullSecrets: - name: {{ .Release.Name }}-regsecret - restartPolicy: Never + restartPolicy: OnFailure containers: - name: pgdump image: "{{ $.Files.Get "images/postgres-backup.tag" | trim }}" diff --git a/packages/apps/rabbitmq/Chart.yaml b/packages/apps/rabbitmq/Chart.yaml index 2218642f..3aa54260 100644 --- a/packages/apps/rabbitmq/Chart.yaml +++ b/packages/apps/rabbitmq/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.5.0 +version: 0.6.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/rabbitmq/templates/_resources.tpl b/packages/apps/rabbitmq/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/rabbitmq/templates/_resources.tpl +++ b/packages/apps/rabbitmq/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/redis/Chart.yaml b/packages/apps/redis/Chart.yaml index 07556e67..2a07e2c0 100644 --- a/packages/apps/redis/Chart.yaml +++ b/packages/apps/redis/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.6.0 +version: 0.7.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/redis/templates/_resources.tpl b/packages/apps/redis/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/redis/templates/_resources.tpl +++ b/packages/apps/redis/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/tcp-balancer/Chart.yaml b/packages/apps/tcp-balancer/Chart.yaml index 9d701dcd..5955c5be 100644 --- a/packages/apps/tcp-balancer/Chart.yaml +++ b/packages/apps/tcp-balancer/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.3.0 +version: 0.4.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/tcp-balancer/templates/_resources.tpl b/packages/apps/tcp-balancer/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/tcp-balancer/templates/_resources.tpl +++ b/packages/apps/tcp-balancer/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/apps/tenant/Chart.yaml b/packages/apps/tenant/Chart.yaml index bba14724..5582dc71 100644 --- a/packages/apps/tenant/Chart.yaml +++ b/packages/apps/tenant/Chart.yaml @@ -4,4 +4,4 @@ description: Separated tenant namespace icon: /logos/tenant.svg type: application -version: 1.9.1 +version: 1.9.2 diff --git a/packages/apps/tenant/README.md b/packages/apps/tenant/README.md index f43db79a..cc26c830 100644 --- a/packages/apps/tenant/README.md +++ b/packages/apps/tenant/README.md @@ -4,36 +4,55 @@ A tenant is the main unit of security on the platform. The closest analogy would Tenants can be created recursively and are subject to the following rules: -### Higher-level tenants can access lower-level ones. +### Tenant naming -Higher-level tenants can view and manage the applications of all their children. +Tenant names must be alphanumeric. +Using dashes (`-`) in tenant names is not allowed, unlike with other services. +This limitation exists to keep consistent naming in tenants, nested tenants, and services deployed in them. -### Each tenant has its own domain +For example: -By default (unless otherwise specified), it inherits the domain of its parent with a prefix of its name, for example, if the parent had the domain `example.org`, then `tenant-foo` would get the domain `foo.example.org` by default. +- The root tenant is named `root`, but internally it's referenced as `tenant-root`. +- A nested tenant could be named `foo`, which would result in `tenant-foo` in service names and URLs. +- However, a tenant can not be named `foo-bar`, because parsing names such as `tenant-foo-bar` would be ambiguous. + +### Unique domains + +Each tenant has its own domain. +By default, (unless otherwise specified), it inherits the domain of its parent with a prefix of its name. +For example, if the parent had the domain `example.org`, then `tenant-foo` would get the domain `foo.example.org` by default. Kubernetes clusters created in this tenant namespace would get domains like: `kubernetes-cluster.foo.example.org` Example: -``` +```text tenant-root (example.org) └── tenant-foo (foo.example.org) └── kubernetes-cluster1 (kubernetes-cluster1.foo.example.org) ``` -### Lower-level tenants can access the cluster services of their parent (provided they do not run their own) +### Nesting tenants and reusing parent services -Thus, you can create `tenant-u1` with a set of services like `etcd`, `ingress`, `monitoring`. And create another tenant namespace `tenant-u2` inside of `tenant-u1`. +Tenants can be nested. +A tenant administrator can create nested tenants using the "Tenant" application from the catalogue. + +Higher-level tenants can view and manage the applications of all their children tenants. +If a tenant does not run their own cluster services, it can access ones of its parent. + +For example, you create: +- Tenant `tenant-u1` with a set of services like `etcd`, `ingress`, `monitoring`. +- Tenant `tenant-u2` nested in `tenant-u1`. Let's see what will happen when you run Kubernetes and Postgres under `tenant-u2` namespace. -Since `tenant-u2` does not have its own cluster services like `etcd`, `ingress`, and `monitoring`, the applications will use the cluster services of the parent tenant. +Since `tenant-u2` does not have its own cluster services like `etcd`, `ingress`, and `monitoring`, +the applications running in `tenant-u2` will use the cluster services of the parent tenant. + This in turn means: -- The Kubernetes cluster data will be stored in etcd for `tenant-u1`. -- Access to the cluster will be through the common ingress of `tenant-u1`. -- Essentially, all metrics will be collected in the monitoring from `tenant-u1`, and only it will have access to them. - +- The Kubernetes cluster data will be stored in `etcd` for `tenant-u1`. +- Access to the cluster will be through the common `ingress` of `tenant-u1`. +- Essentially, all metrics will be collected in the `monitoring` from `tenant-u1`, and only that tenant will have access to them. Example: ``` diff --git a/packages/apps/tenant/templates/networkpolicy.yaml b/packages/apps/tenant/templates/networkpolicy.yaml index 7815162f..6d80f996 100644 --- a/packages/apps/tenant/templates/networkpolicy.yaml +++ b/packages/apps/tenant/templates/networkpolicy.yaml @@ -24,6 +24,7 @@ spec: ingress: - fromEntities: - world + - cluster egress: - toEntities: - world diff --git a/packages/apps/versions_map b/packages/apps/versions_map index a1175417..be176c6a 100644 --- a/packages/apps/versions_map +++ b/packages/apps/versions_map @@ -8,7 +8,8 @@ clickhouse 0.5.0 0f312d5c clickhouse 0.6.0 1ec10165 clickhouse 0.6.1 c62a83a7 clickhouse 0.6.2 8267072d -clickhouse 0.7.0 HEAD +clickhouse 0.7.0 93bdf411 +clickhouse 0.9.0 HEAD ferretdb 0.1.0 e9716091 ferretdb 0.1.1 91b0499a ferretdb 0.2.0 6c5cf5bf @@ -16,12 +17,14 @@ ferretdb 0.3.0 b8e33d19 ferretdb 0.4.0 b40e1b09 ferretdb 0.4.1 1ec10165 ferretdb 0.4.2 8267072d -ferretdb 0.5.0 HEAD +ferretdb 0.5.0 93bdf411 +ferretdb 0.6.0 HEAD http-cache 0.1.0 263e47be http-cache 0.2.0 53f2365e http-cache 0.3.0 6c5cf5bf http-cache 0.3.1 0f312d5c -http-cache 0.4.0 HEAD +http-cache 0.4.0 93bdf411 +http-cache 0.5.0 HEAD kafka 0.1.0 f7eaab0a kafka 0.2.0 c0685f43 kafka 0.2.1 dfbc210b @@ -32,7 +35,8 @@ kafka 0.3.1 c62a83a7 kafka 0.3.2 93c46161 kafka 0.3.3 8267072d kafka 0.4.0 85ec09b8 -kafka 0.5.0 HEAD +kafka 0.5.0 93bdf411 +kafka 0.6.0 HEAD kubernetes 0.1.0 263e47be kubernetes 0.2.0 53f2365e kubernetes 0.3.0 007d414f @@ -59,7 +63,9 @@ kubernetes 0.16.0 077045b0 kubernetes 0.17.0 1fbbfcd0 kubernetes 0.17.1 fd240701 kubernetes 0.18.0 721c12a7 -kubernetes 0.18.1 HEAD +kubernetes 0.19.0 93bdf411 +kubernetes 0.20.0 609e7ede +kubernetes 0.20.1 HEAD mysql 0.1.0 263e47be mysql 0.2.0 c24a103f mysql 0.3.0 53f2365e @@ -68,14 +74,16 @@ mysql 0.5.0 b40e1b09 mysql 0.5.1 0f312d5c mysql 0.5.2 1ec10165 mysql 0.5.3 8267072d -mysql 0.6.0 HEAD +mysql 0.6.0 93bdf411 +mysql 0.7.0 HEAD nats 0.1.0 e9716091 nats 0.2.0 6c5cf5bf nats 0.3.0 78366f19 nats 0.3.1 c62a83a7 nats 0.4.0 898374b5 nats 0.4.1 8267072d -nats 0.5.0 HEAD +nats 0.5.0 93bdf411 +nats 0.6.0 HEAD postgres 0.1.0 263e47be postgres 0.2.0 53f2365e postgres 0.2.1 d7cfa53c @@ -89,7 +97,9 @@ postgres 0.7.0 4b90bf5a postgres 0.7.1 1ec10165 postgres 0.8.0 4e68e65c postgres 0.9.0 8267072d -postgres 0.10.0 HEAD +postgres 0.10.0 721c12a7 +postgres 0.10.1 93bdf411 +postgres 0.11.0 HEAD rabbitmq 0.1.0 263e47be rabbitmq 0.2.0 53f2365e rabbitmq 0.3.0 6c5cf5bf @@ -98,17 +108,20 @@ rabbitmq 0.4.1 1128d0cb rabbitmq 0.4.2 4b90bf5a rabbitmq 0.4.3 1ec10165 rabbitmq 0.4.4 8267072d -rabbitmq 0.5.0 HEAD +rabbitmq 0.5.0 93bdf411 +rabbitmq 0.6.0 HEAD redis 0.1.1 263e47be redis 0.2.0 53f2365e redis 0.3.0 6c5cf5bf redis 0.3.1 c62a83a7 redis 0.4.0 84f3ccc0 redis 0.5.0 4e68e65c -redis 0.6.0 HEAD +redis 0.6.0 93bdf411 +redis 0.7.0 HEAD tcp-balancer 0.1.0 263e47be tcp-balancer 0.2.0 53f2365e -tcp-balancer 0.3.0 HEAD +tcp-balancer 0.3.0 93bdf411 +tcp-balancer 0.4.0 HEAD tenant 0.1.4 afc997ef tenant 0.1.5 e3ab858a tenant 1.0.0 263e47be @@ -130,7 +143,8 @@ tenant 1.6.8 bc95159a tenant 1.7.0 24fa7222 tenant 1.8.0 160e4e2a tenant 1.9.0 728743db -tenant 1.9.1 HEAD +tenant 1.9.1 721c12a7 +tenant 1.9.2 HEAD virtual-machine 0.1.4 f2015d65 virtual-machine 0.1.5 263e47be virtual-machine 0.2.0 c0685f43 @@ -143,7 +157,9 @@ virtual-machine 0.7.1 0ab39f20 virtual-machine 0.8.0 3fa4dd3a virtual-machine 0.8.1 93c46161 virtual-machine 0.8.2 de19450f -virtual-machine 0.9.0 HEAD +virtual-machine 0.9.0 721c12a7 +virtual-machine 0.9.1 93bdf411 +virtual-machine 0.10.0 HEAD vm-disk 0.1.0 d971f2ff vm-disk 0.1.1 HEAD vm-instance 0.1.0 1ec10165 @@ -153,9 +169,11 @@ vm-instance 0.4.0 e23286a3 vm-instance 0.4.1 0ab39f20 vm-instance 0.5.0 3fa4dd3a vm-instance 0.5.1 de19450f -vm-instance 0.6.0 HEAD +vm-instance 0.6.0 721c12a7 +vm-instance 0.7.0 HEAD vpn 0.1.0 263e47be vpn 0.2.0 53f2365e vpn 0.3.0 6c5cf5bf vpn 0.3.1 1ec10165 -vpn 0.4.0 HEAD +vpn 0.4.0 93bdf411 +vpn 0.5.0 HEAD diff --git a/packages/apps/virtual-machine/Chart.yaml b/packages/apps/virtual-machine/Chart.yaml index b4ad45b5..000ccba6 100644 --- a/packages/apps/virtual-machine/Chart.yaml +++ b/packages/apps/virtual-machine/Chart.yaml @@ -17,10 +17,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.9.0 +version: 0.10.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: 0.9.0 +appVersion: 0.10.0 diff --git a/packages/apps/virtual-machine/Makefile b/packages/apps/virtual-machine/Makefile index f3de3546..5d31cacf 100644 --- a/packages/apps/virtual-machine/Makefile +++ b/packages/apps/virtual-machine/Makefile @@ -9,4 +9,4 @@ generate: && yq -i -o json ".properties.instanceProfile.optional=true | .properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json yq -i -o json '.properties.externalPorts.items.type = "integer"' values.schema.json yq -i -o json '.properties.systemDisk.properties.image.enum = ["ubuntu", "cirros", "alpine", "fedora", "talos"]' values.schema.json - yq -i -o json '.properties.externalMethod.enum = ["WholeIP", "PortList"]' values.schema.json + yq -i -o json '.properties.externalMethod.enum = ["PortList", "WholeIP"]' values.schema.json diff --git a/packages/apps/virtual-machine/README.md b/packages/apps/virtual-machine/README.md index bb33570b..8c9b382c 100644 --- a/packages/apps/virtual-machine/README.md +++ b/packages/apps/virtual-machine/README.md @@ -39,7 +39,7 @@ virtctl ssh <user>@<vm> | Name | Description | Value | | ------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------ | | `external` | Enable external access from outside the cluster | `false` | -| `externalMethod` | specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList` | `WholeIP` | +| `externalMethod` | specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList` | `PortList` | | `externalPorts` | Specify ports to forward from outside the cluster | `[]` | | `running` | Determines if the virtual machine should be running | `true` | | `instanceType` | Virtual Machine instance type | `u1.medium` | diff --git a/packages/apps/virtual-machine/templates/vm.yaml b/packages/apps/virtual-machine/templates/vm.yaml index 67f192e7..1d94799b 100644 --- a/packages/apps/virtual-machine/templates/vm.yaml +++ b/packages/apps/virtual-machine/templates/vm.yaml @@ -27,10 +27,7 @@ spec: - metadata: name: {{ include "virtual-machine.fullname" . }} spec: - pvc: - volumeMode: Block - accessModes: - - ReadWriteMany + storage: resources: requests: storage: {{ .Values.systemDisk.storage | quote }} @@ -74,7 +71,8 @@ spec: {{- if .Values.gpus }} gpus: {{- range $i, $gpu := .Values.gpus }} - - deviceName: {{ $gpu.name }} + - name: gpu{{ add $i 1 }} + deviceName: {{ $gpu.name }} {{- end }} {{- end }} disks: diff --git a/packages/apps/virtual-machine/values.schema.json b/packages/apps/virtual-machine/values.schema.json index 861d4da4..ea0efd4c 100644 --- a/packages/apps/virtual-machine/values.schema.json +++ b/packages/apps/virtual-machine/values.schema.json @@ -10,10 +10,10 @@ "externalMethod": { "type": "string", "description": "specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList`", - "default": "WholeIP", + "default": "PortList", "enum": [ - "WholeIP", - "PortList" + "PortList", + "WholeIP" ] }, "externalPorts": { diff --git a/packages/apps/virtual-machine/values.yaml b/packages/apps/virtual-machine/values.yaml index 6cccbad1..191a86a5 100644 --- a/packages/apps/virtual-machine/values.yaml +++ b/packages/apps/virtual-machine/values.yaml @@ -4,7 +4,7 @@ ## @param externalMethod specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList` ## @param externalPorts [array] Specify ports to forward from outside the cluster external: false -externalMethod: WholeIP +externalMethod: PortList externalPorts: - 22 diff --git a/packages/apps/vm-instance/Chart.yaml b/packages/apps/vm-instance/Chart.yaml index 5f70145f..8011ca1f 100644 --- a/packages/apps/vm-instance/Chart.yaml +++ b/packages/apps/vm-instance/Chart.yaml @@ -17,10 +17,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.6.0 +version: 0.7.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: 0.6.0 +appVersion: 0.7.0 diff --git a/packages/apps/vm-instance/Makefile b/packages/apps/vm-instance/Makefile index 5b2aebab..3a9a0fd8 100644 --- a/packages/apps/vm-instance/Makefile +++ b/packages/apps/vm-instance/Makefile @@ -9,4 +9,4 @@ generate: PREFERENCES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/preferences.yaml | yq 'split(" ") | . + [""]' -o json) \ && yq -i -o json ".properties.instanceProfile.optional=true | .properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json yq -i -o json '.properties.externalPorts.items.type = "integer"' values.schema.json - yq -i -o json '.properties.externalMethod.enum = ["WholeIP", "PortList"]' values.schema.json + yq -i -o json '.properties.externalMethod.enum = ["PortList", "WholeIP"]' values.schema.json diff --git a/packages/apps/vm-instance/README.md b/packages/apps/vm-instance/README.md index 273c1f15..611595a0 100644 --- a/packages/apps/vm-instance/README.md +++ b/packages/apps/vm-instance/README.md @@ -39,7 +39,7 @@ virtctl ssh <user>@<vm> | Name | Description | Value | | ------------------ | ---------------------------------------------------------------------------------------------------------- | ----------- | | `external` | Enable external access from outside the cluster | `false` | -| `externalMethod` | specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList` | `WholeIP` | +| `externalMethod` | specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList` | `PortList` | | `externalPorts` | Specify ports to forward from outside the cluster | `[]` | | `running` | Determines if the virtual machine should be running | `true` | | `instanceType` | Virtual Machine instance type | `u1.medium` | diff --git a/packages/apps/vm-instance/templates/vm.yaml b/packages/apps/vm-instance/templates/vm.yaml index 4a8ed2a4..8b647e70 100644 --- a/packages/apps/vm-instance/templates/vm.yaml +++ b/packages/apps/vm-instance/templates/vm.yaml @@ -46,7 +46,8 @@ spec: {{- if .Values.gpus }} gpus: {{- range $i, $gpu := .Values.gpus }} - - deviceName: {{ $gpu.name }} + - name: gpu{{ add $i 1 }} + deviceName: {{ $gpu.name }} {{- end }} {{- end }} disks: diff --git a/packages/apps/vm-instance/values.schema.json b/packages/apps/vm-instance/values.schema.json index f4dd2076..8ce71cdb 100644 --- a/packages/apps/vm-instance/values.schema.json +++ b/packages/apps/vm-instance/values.schema.json @@ -10,10 +10,10 @@ "externalMethod": { "type": "string", "description": "specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList`", - "default": "WholeIP", + "default": "PortList", "enum": [ - "WholeIP", - "PortList" + "PortList", + "WholeIP" ] }, "externalPorts": { diff --git a/packages/apps/vm-instance/values.yaml b/packages/apps/vm-instance/values.yaml index eb68ced2..4b21423d 100644 --- a/packages/apps/vm-instance/values.yaml +++ b/packages/apps/vm-instance/values.yaml @@ -4,7 +4,7 @@ ## @param externalMethod specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList` ## @param externalPorts [array] Specify ports to forward from outside the cluster external: false -externalMethod: WholeIP +externalMethod: PortList externalPorts: - 22 diff --git a/packages/apps/vpn/Chart.yaml b/packages/apps/vpn/Chart.yaml index c82e77dd..4382233a 100644 --- a/packages/apps/vpn/Chart.yaml +++ b/packages/apps/vpn/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.0 +version: 0.5.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/vpn/templates/_resources.tpl b/packages/apps/vpn/templates/_resources.tpl index 7ada56d4..6539c99a 100644 --- a/packages/apps/vpn/templates/_resources.tpl +++ b/packages/apps/vpn/templates/_resources.tpl @@ -11,35 +11,34 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} {{- $presets := dict "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) "large" (dict - "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) "2xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) }} {{- if hasKey $presets .type -}} diff --git a/packages/core/installer/images/talos/profiles/initramfs.yaml b/packages/core/installer/images/talos/profiles/initramfs.yaml index af5f34cc..2898ed61 100644 --- a/packages/core/installer/images/talos/profiles/initramfs.yaml +++ b/packages/core/installer/images/talos/profiles/initramfs.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.9.5 +version: v1.10.1 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: ghcr.io/siderolabs/installer:v1.9.5 + imageRef: ghcr.io/siderolabs/installer:v1.10.1 systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250311 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250410 - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20241110 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250311 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250410 - imageRef: ghcr.io/siderolabs/i915-ucode:20241110 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250311 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250410 - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250311 - - imageRef: ghcr.io/siderolabs/drbd:9.2.12-v1.9.5 - - imageRef: ghcr.io/siderolabs/zfs:2.2.7-v1.9.5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250410 + - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.1 + - imageRef: ghcr.io/siderolabs/zfs:2.3.1-v1.10.1 output: kind: initramfs imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/installer.yaml b/packages/core/installer/images/talos/profiles/installer.yaml index b717ba3e..594c1e09 100644 --- a/packages/core/installer/images/talos/profiles/installer.yaml +++ b/packages/core/installer/images/talos/profiles/installer.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.9.5 +version: v1.10.1 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: ghcr.io/siderolabs/installer:v1.9.5 + imageRef: ghcr.io/siderolabs/installer:v1.10.1 systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250311 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250410 - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20241110 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250311 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250410 - imageRef: ghcr.io/siderolabs/i915-ucode:20241110 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250311 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250410 - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250311 - - imageRef: ghcr.io/siderolabs/drbd:9.2.12-v1.9.5 - - imageRef: ghcr.io/siderolabs/zfs:2.2.7-v1.9.5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250410 + - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.1 + - imageRef: ghcr.io/siderolabs/zfs:2.3.1-v1.10.1 output: kind: installer imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/iso.yaml b/packages/core/installer/images/talos/profiles/iso.yaml index c10d43c6..5a416e99 100644 --- a/packages/core/installer/images/talos/profiles/iso.yaml +++ b/packages/core/installer/images/talos/profiles/iso.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.9.5 +version: v1.10.1 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: ghcr.io/siderolabs/installer:v1.9.5 + imageRef: ghcr.io/siderolabs/installer:v1.10.1 systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250311 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250410 - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20241110 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250311 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250410 - imageRef: ghcr.io/siderolabs/i915-ucode:20241110 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250311 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250410 - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250311 - - imageRef: ghcr.io/siderolabs/drbd:9.2.12-v1.9.5 - - imageRef: ghcr.io/siderolabs/zfs:2.2.7-v1.9.5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250410 + - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.1 + - imageRef: ghcr.io/siderolabs/zfs:2.3.1-v1.10.1 output: kind: iso imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/kernel.yaml b/packages/core/installer/images/talos/profiles/kernel.yaml index 462aaaac..14f00f8b 100644 --- a/packages/core/installer/images/talos/profiles/kernel.yaml +++ b/packages/core/installer/images/talos/profiles/kernel.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.9.5 +version: v1.10.1 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: ghcr.io/siderolabs/installer:v1.9.5 + imageRef: ghcr.io/siderolabs/installer:v1.10.1 systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250311 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250410 - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20241110 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250311 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250410 - imageRef: ghcr.io/siderolabs/i915-ucode:20241110 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250311 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250410 - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250311 - - imageRef: ghcr.io/siderolabs/drbd:9.2.12-v1.9.5 - - imageRef: ghcr.io/siderolabs/zfs:2.2.7-v1.9.5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250410 + - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.1 + - imageRef: ghcr.io/siderolabs/zfs:2.3.1-v1.10.1 output: kind: kernel imageOptions: {} diff --git a/packages/core/installer/images/talos/profiles/metal.yaml b/packages/core/installer/images/talos/profiles/metal.yaml index e3f5a8e9..e559318a 100644 --- a/packages/core/installer/images/talos/profiles/metal.yaml +++ b/packages/core/installer/images/talos/profiles/metal.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.9.5 +version: v1.10.1 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: ghcr.io/siderolabs/installer:v1.9.5 + imageRef: ghcr.io/siderolabs/installer:v1.10.1 systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250311 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250410 - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20241110 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250311 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250410 - imageRef: ghcr.io/siderolabs/i915-ucode:20241110 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250311 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250410 - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250311 - - imageRef: ghcr.io/siderolabs/drbd:9.2.12-v1.9.5 - - imageRef: ghcr.io/siderolabs/zfs:2.2.7-v1.9.5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250410 + - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.1 + - imageRef: ghcr.io/siderolabs/zfs:2.3.1-v1.10.1 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } diff --git a/packages/core/installer/images/talos/profiles/nocloud.yaml b/packages/core/installer/images/talos/profiles/nocloud.yaml index e781edc1..dab8ea38 100644 --- a/packages/core/installer/images/talos/profiles/nocloud.yaml +++ b/packages/core/installer/images/talos/profiles/nocloud.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: nocloud secureboot: false -version: v1.9.5 +version: v1.10.1 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: ghcr.io/siderolabs/installer:v1.9.5 + imageRef: ghcr.io/siderolabs/installer:v1.10.1 systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250311 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250410 - imageRef: ghcr.io/siderolabs/amdgpu-firmware:20241110 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250311 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250410 - imageRef: ghcr.io/siderolabs/i915-ucode:20241110 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250311 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250410 - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250311 - - imageRef: ghcr.io/siderolabs/drbd:9.2.12-v1.9.5 - - imageRef: ghcr.io/siderolabs/zfs:2.2.7-v1.9.5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250410 + - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.1 + - imageRef: ghcr.io/siderolabs/zfs:2.3.1-v1.10.1 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index bc00caf1..d582a949 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.30.2@sha256:59996588b5d59b5593fb34442b2f2ed8ef466d138b229a8d37beb6f70141a690 + image: ghcr.io/cozystack/cozystack/installer:v0.31.0-rc.3@sha256:5fc6b88de670878b66f2b5bf381b89b68253ab3e69ff1cb7359470bc65beb3fa diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index 08c2da4a..8c37a023 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -161,7 +161,7 @@ releases: releaseName: piraeus-operator chart: cozy-piraeus-operator namespace: cozy-linstor - dependsOn: [cilium,cert-manager,victoria-metrics-operator] + dependsOn: [cilium,cert-manager] - name: snapshot-controller releaseName: snapshot-controller diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 74806d9e..71191025 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -134,6 +134,11 @@ releases: namespace: cozy-kubevirt privileged: true dependsOn: [cilium,kubeovn,kubevirt-operator] + {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} + {{- if $cpuAllocationRatio }} + values: + cpuAllocationRatio: {{ $cpuAllocationRatio }} + {{- end }} - name: kubevirt-instancetypes releaseName: kubevirt-instancetypes @@ -255,72 +260,15 @@ releases: releaseName: dashboard chart: cozy-dashboard namespace: cozy-dashboard - dependsOn: [cilium,kubeovn,keycloak-configure] values: - kubeapps: - {{- if .Capabilities.APIVersions.Has "source.toolkit.fluxcd.io/v1" }} - {{- with (lookup "source.toolkit.fluxcd.io/v1" "HelmRepository" "cozy-public" "").items }} - redis: - master: - podAnnotations: - {{- range $index, $repo := . }} - {{- with (($repo.status).artifact).revision }} - repository.cozystack.io/{{ $repo.metadata.name }}: {{ quote . }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - frontend: - resourcesPreset: "none" - dashboard: - resourcesPreset: "none" - {{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} - {{- $branding := dig "data" "branding" "" $cozystackBranding }} - {{- if $branding }} - customLocale: - "Kubeapps": {{ $branding }} - {{- end }} - customStyle: | - {{- $logoImage := dig "data" "logo" "" $cozystackBranding }} - {{- if $logoImage }} - .kubeapps-logo { - background-image: {{ $logoImage }} - } - {{- end }} - #serviceaccount-selector { - display: none; - } - .login-moreinfo { - display: none; - } - a[href="#/docs"] { - display: none; - } - .login-group .clr-form-control .clr-control-label { - display: none; - } - .appview-separator div.appview-first-row div.center { - display: none; - } - .appview-separator div.appview-first-row section[aria-labelledby="app-secrets"] { - display: none; - } - .appview-first-row section[aria-labelledby="access-urls-title"] { - width: 100%; - } - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig }} - {{- if $dashboardKCValues }} - valuesFrom: - - kind: ConfigMap - name: kubeapps-auth-config - valuesKey: values.yaml - {{- end }} - + {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} + {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }} + {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} + dependsOn: + - cilium + - kubeovn {{- if eq $oidcEnabled "true" }} - dependsOn: [keycloak-configure] - {{- else }} - dependsOn: [] + - keycloak-configure {{- end }} - name: kamaji diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index f082b3bb..12addedb 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -155,66 +155,9 @@ releases: chart: cozy-dashboard namespace: cozy-dashboard values: - kubeapps: - {{- if .Capabilities.APIVersions.Has "source.toolkit.fluxcd.io/v1" }} - {{- with (lookup "source.toolkit.fluxcd.io/v1" "HelmRepository" "cozy-public" "").items }} - redis: - master: - podAnnotations: - {{- range $index, $repo := . }} - {{- with (($repo.status).artifact).revision }} - repository.cozystack.io/{{ $repo.metadata.name }}: {{ quote . }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - frontend: - resourcesPreset: "none" - dashboard: - resourcesPreset: "none" - {{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} - {{- $branding := dig "data" "branding" "" $cozystackBranding }} - {{- if $branding }} - customLocale: - "Kubeapps": {{ $branding }} - {{- end }} - customStyle: | - {{- $logoImage := dig "data" "logo" "" $cozystackBranding }} - {{- if $logoImage }} - .kubeapps-logo { - background-image: {{ $logoImage }} - } - {{- end }} - #serviceaccount-selector { - display: none; - } - .login-moreinfo { - display: none; - } - a[href="#/docs"] { - display: none; - } - .login-group .clr-form-control .clr-control-label { - display: none; - } - .appview-separator div.appview-first-row div.center { - display: none; - } - .appview-separator div.appview-first-row section[aria-labelledby="app-secrets"] { - display: none; - } - .appview-first-row section[aria-labelledby="access-urls-title"] { - width: 100%; - } - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig }} - {{- if $dashboardKCValues }} - valuesFrom: - - kind: ConfigMap - name: kubeapps-auth-config - valuesKey: values.yaml - {{- end }} - + {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} + {{- $dashboardKCValues := dig "data" "values.yaml" (dict) $dashboardKCconfig }} + {{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }} {{- if eq $oidcEnabled "true" }} dependsOn: [keycloak-configure] {{- else }} diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index b3ab6a86..94edb35b 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -16,3 +16,57 @@ Get IP-addresses of master nodes {{- end -}} {{ join "," $ips }} {{- end -}} + +{{- define "cozystack.defaultDashboardValues" -}} +kubeapps: +{{- if .Capabilities.APIVersions.Has "source.toolkit.fluxcd.io/v1" }} +{{- with (lookup "source.toolkit.fluxcd.io/v1" "HelmRepository" "cozy-public" "").items }} + redis: + master: + podAnnotations: + {{- range $index, $repo := . }} + {{- with (($repo.status).artifact).revision }} + repository.cozystack.io/{{ $repo.metadata.name }}: {{ quote . }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} + frontend: + resourcesPreset: "none" + dashboard: + resourcesPreset: "none" + {{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} + {{- $branding := dig "data" "branding" "" $cozystackBranding }} + {{- if $branding }} + customLocale: + "Kubeapps": {{ $branding }} + {{- end }} + customStyle: | + {{- $logoImage := dig "data" "logo" "" $cozystackBranding }} + {{- if $logoImage }} + .kubeapps-logo { + background-image: {{ $logoImage }} + } + {{- end }} + #serviceaccount-selector { + display: none; + } + .login-moreinfo { + display: none; + } + a[href="#/docs"] { + display: none; + } + .login-group .clr-form-control .clr-control-label { + display: none; + } + .appview-separator div.appview-first-row div.center { + display: none; + } + .appview-separator div.appview-first-row section[aria-labelledby="app-secrets"] { + display: none; + } + .appview-first-row section[aria-labelledby="access-urls-title"] { + width: 100%; + } +{{- end }} diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml index f1872870..a24744b8 100644 --- a/packages/core/platform/templates/apps.yaml +++ b/packages/core/platform/templates/apps.yaml @@ -8,7 +8,7 @@ {{- $host = index $cozyConfig.data "root-host" }} {{- end }} {{- end }} -{{- $tenantRoot := list }} +{{- $tenantRoot := dict }} {{- if .Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} {{- $tenantRoot = lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" "tenant-root" "tenant-root" }} {{- end }} @@ -37,7 +37,7 @@ metadata: labels: cozystack.io/ui: "true" spec: - interval: 1m + interval: 0s releaseName: tenant-root install: remediation: diff --git a/packages/core/platform/templates/helmreleases.yaml b/packages/core/platform/templates/helmreleases.yaml index ef04d3cc..17b373be 100644 --- a/packages/core/platform/templates/helmreleases.yaml +++ b/packages/core/platform/templates/helmreleases.yaml @@ -55,6 +55,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system + version: '>= 0.0.0-0' {{- with $x.valuesFiles }} valuesFiles: {{- toYaml $x.valuesFiles | nindent 6 }} @@ -71,17 +72,6 @@ spec: {{- toYaml . | nindent 4}} {{- end }} - {{- if $x.valuesFrom }} - valuesFrom: - {{- range $source := $x.valuesFrom }} - - kind: {{ $source.kind }} - name: {{ $source.name }} - {{- if $source.valuesKey }} - valuesKey: {{ $source.valuesKey }} - {{- end }} - {{- end }} - {{- end }} - {{- with $x.dependsOn }} dependsOn: {{- range $dep := . }} diff --git a/packages/core/testing/Makefile b/packages/core/testing/Makefile index 747d4507..f3a97eee 100755 --- a/packages/core/testing/Makefile +++ b/packages/core/testing/Makefile @@ -11,20 +11,14 @@ include ../../../scripts/common-envs.mk help: ## Show this help. @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) -show: - helm template -n $(NAMESPACE) $(NAME) . - -apply: ## Create sandbox in existing Kubernetes cluster. - helm template -n $(NAMESPACE) $(NAME) . | kubectl apply -f - - -diff: - helm template -n $(NAMESPACE) $(NAME) . | kubectl diff -f - image: image-e2e-sandbox image-e2e-sandbox: docker buildx build -f images/e2e-sandbox/Dockerfile ../../.. \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/e2e-sandbox:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/e2e-sandbox:latest \ --cache-to type=inline \ @@ -36,30 +30,25 @@ image-e2e-sandbox: yq -i '.e2e.image = strenv(IMAGE)' values.yaml rm -f images/e2e-sandbox.json -test: ## Run the end-to-end tests in existing sandbox. - docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && export COZYSTACK_INSTALLER_YAML=$$(helm template -n cozy-system installer ./packages/core/installer) && hack/e2e.sh' +test: test-cluster test-apps ## Run the end-to-end tests in existing sandbox -test-applications: ## Run the end-to-end tests in existing sandbox for applications. - for app in $(TESTING_APPS); do \ - docker exec ${SANDBOX_NAME} bash -c "/hack/e2e.application.sh $${app}"; \ - done - docker exec ${SANDBOX_NAME} bash -c "kubectl get hr -A | grep -v 'True'" +test-cluster: ## Run the end-to-end for creating a cluster + docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && export COZYSTACK_INSTALLER_YAML=$$(helm template -n cozy-system installer ./packages/core/installer) && hack/cozytest.sh hack/e2e-cluster.bats' + +test-apps: ## Run the end-to-end tests for apps + docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && hack/cozytest.sh hack/e2e-apps.bats' delete: ## Remove sandbox from existing Kubernetes cluster. docker rm -f "${SANDBOX_NAME}" || true exec: ## Opens an interactive shell in the sandbox container. - docker exec -ti "${SANDBOX_NAME}" -- bash - -proxy: sync-hosts ## Enable a SOCKS5 proxy server; mirrord and gost must be installed. - mirrord exec --target deploy/cozystack-e2e-sandbox --target-namespace cozy-e2e-tests -- gost -L=127.0.0.1:10080 - -login: ## Downloads the kubeconfig into a temporary directory and runs a shell with the sandbox environment; mirrord must be installed. - mirrord exec --target deploy/cozystack-e2e-sandbox --target-namespace cozy-e2e-tests -- "$$SHELL" - -sync-hosts: - kubectl exec -n $(NAMESPACE) deploy/cozystack-e2e-$(NAME) -- sh -c 'kubectl get ing -A -o go-template='\''{{ "127.0.0.1 localhost\n"}}{{ range .items }}{{ range .status.loadBalancer.ingress }}{{ .ip }}{{ end }} {{ range .spec.rules }}{{ .host }}{{ end }}{{ "\n" }}{{ end }}'\'' > /etc/hosts' + docker exec -ti "${SANDBOX_NAME}" bash apply: delete - docker run -d --rm --name "${SANDBOX_NAME}" --privileged "$$(yq .e2e.image values.yaml)" sleep infinity + docker run \ + -d --rm --name "${SANDBOX_NAME}" --privileged \ + -e TALOSCONFIG=/workspace/talosconfig \ + -e KUBECONFIG=/workspace/kubeconfig \ + "$$(yq .e2e.image values.yaml)" \ + sleep infinity docker cp "${ROOT_DIR}" "${SANDBOX_NAME}":/workspace diff --git a/packages/core/testing/images/e2e-sandbox/Dockerfile b/packages/core/testing/images/e2e-sandbox/Dockerfile index 8318e982..9d948e7c 100755 --- a/packages/core/testing/images/e2e-sandbox/Dockerfile +++ b/packages/core/testing/images/e2e-sandbox/Dockerfile @@ -4,14 +4,16 @@ ARG KUBECTL_VERSION=1.32.0 ARG TALOSCTL_VERSION=1.9.5 ARG HELM_VERSION=3.16.4 -RUN apt-get update -RUN apt-get -y install genisoimage qemu-kvm qemu-utils iproute2 iptables wget xz-utils netcat curl jq make git -RUN curl -LO "https://github.com/siderolabs/talos/releases/download/v${TALOSCTL_VERSION}/talosctl-linux-amd64" \ - && chmod +x talosctl-linux-amd64 \ - && mv talosctl-linux-amd64 /usr/local/bin/talosctl -RUN curl -LO "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl" \ - && chmod +x kubectl \ - && mv kubectl /usr/local/bin/kubectl -RUN curl -sSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash -s - --version "v${HELM_VERSION}" -RUN wget https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 -O /usr/local/bin/yq && chmod +x /usr/local/bin/yq -RUN curl -s https://fluxcd.io/install.sh | bash +ARG TARGETOS +ARG TARGETARCH + +RUN apt update -q +RUN apt install -yq --no-install-recommends genisoimage ca-certificates qemu-kvm qemu-utils iproute2 iptables wget xz-utils netcat curl jq make git +RUN curl -sSL "https://github.com/siderolabs/talos/releases/download/v${TALOSCTL_VERSION}/talosctl-${TARGETOS}-${TARGETARCH}" -o /usr/local/bin/talosctl \ + && chmod +x /usr/local/bin/talosctl +RUN curl -sSL "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/${TARGETOS}/${TARGETARCH}/kubectl" -o /usr/local/bin/kubectl \ + && chmod +x /usr/local/bin/kubectl +RUN curl -sSL "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3" | bash -s - --version "v${HELM_VERSION}" +RUN curl -sSL "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_${TARGETOS}_${TARGETARCH}" -o /usr/local/bin/yq \ + && chmod +x /usr/local/bin/yq +RUN curl -sSL "https://fluxcd.io/install.sh" | bash diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index ce5b1eeb..f511dab5 100755 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.30.2@sha256:31273d6b42dc88c2be2ff9ba64564d1b12e70ae8a5480953341b0d113ac7d4bd + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.31.0-rc.3@sha256:8de0a8900994cb55f74ba25d265eeecac9958b07cdb8f86b9284b9f23668d2bb diff --git a/packages/extra/Makefile b/packages/extra/Makefile index 7212987d..f2071677 100644 --- a/packages/extra/Makefile +++ b/packages/extra/Makefile @@ -1,14 +1,8 @@ -OUT=../../_out/repos/extra -TMP=../../_out/repos/extra/historical +OUT=../_out/repos/extra +TMP := $(shell mktemp -d) repo: - rm -rf "$(OUT)" - mkdir -p "$(OUT)" - awk '$$3 != "HEAD" {print "mkdir -p $(TMP)/" $$1 "-" $$2}' versions_map | sh -ex - awk '$$3 != "HEAD" {print "git archive " $$3 " " $$1 " | tar -xf- --strip-components=1 -C $(TMP)/" $$1 "-" $$2 }' versions_map | sh -ex - helm package -d "$(OUT)" $$(find . $(TMP) -mindepth 2 -maxdepth 2 -name Chart.yaml | awk 'sub("/Chart.yaml", "")' | sort -V) - cd "$(OUT)" && helm repo index . --url http://cozystack.cozy-system.svc/repos/extra - rm -rf "$(TMP)" + cd .. && ../hack/package_chart.sh extra $(OUT) $(TMP) library fix-chartnames: find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed "s/^name: .*/name: $$i/" "$$i/Chart.yaml"; done diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 499055a6..662c044e 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.30.2@sha256:307d382f75f1dcb39820c73b93b2ce576cdb6d58032679bda7d926999c677900 +ghcr.io/cozystack/cozystack/matchbox:v0.31.0-rc.3@sha256:8b65a160333830bf4711246ae78f26095e3b33667440bf1bbdd36db60a7f92e2 diff --git a/packages/extra/info/Chart.yaml b/packages/extra/info/Chart.yaml index 2865c6df..d0a06e9f 100644 --- a/packages/extra/info/Chart.yaml +++ b/packages/extra/info/Chart.yaml @@ -3,4 +3,4 @@ name: info description: Info icon: /logos/info.svg type: application -version: 1.0.0 +version: 1.0.1 diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index ff8127d2..d960a587 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -11,6 +11,13 @@ {{- $k8sClient := index $k8sClientSecret.data "client-secret-key" | b64dec }} {{- $rootSaConfigMap := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} {{- $k8sCa := index $rootSaConfigMap.data "ca.crt" | b64enc }} + +{{- if .Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} +{{- $tenantRoot := lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" "tenant-root" "tenant-root" }} +{{- if and $tenantRoot $tenantRoot.spec $tenantRoot.spec.values $tenantRoot.spec.values.host }} +{{- $host = $tenantRoot.spec.values.host }} +{{- end }} +{{- end }} --- apiVersion: v1 kind: Secret diff --git a/packages/extra/ingress/Chart.yaml b/packages/extra/ingress/Chart.yaml index 25d86de0..93807c89 100644 --- a/packages/extra/ingress/Chart.yaml +++ b/packages/extra/ingress/Chart.yaml @@ -3,4 +3,4 @@ name: ingress description: NGINX Ingress Controller icon: /logos/ingress-nginx.svg type: application -version: 1.5.0 +version: 1.6.0 diff --git a/packages/extra/ingress/README.md b/packages/extra/ingress/README.md index af395dfe..ab4ed3d9 100644 --- a/packages/extra/ingress/README.md +++ b/packages/extra/ingress/README.md @@ -4,13 +4,10 @@ ### Common parameters -| Name | Description | Value | -| ----------------- | ----------------------------------------------------------------- | ------- | -| `replicas` | Number of ingress-nginx replicas | `2` | -| `externalIPs` | List of externalIPs for service. | `[]` | -| `whitelist` | List of client networks | `[]` | -| `clouflareProxy` | Restoring original visitor IPs when Cloudflare proxied is enabled | `false` | -| `dashboard` | Should ingress serve Cozystack service dashboard | `false` | -| `cdiUploadProxy` | Should ingress serve CDI upload proxy | `false` | -| `virtExportProxy` | Should ingress serve KubeVirt export proxy | `false` | +| Name | Description | Value | +| ---------------- | ----------------------------------------------------------------- | ------- | +| `replicas` | Number of ingress-nginx replicas | `2` | +| `externalIPs` | List of externalIPs for service. | `[]` | +| `whitelist` | List of client networks | `[]` | +| `clouflareProxy` | Restoring original visitor IPs when Cloudflare proxied is enabled | `false` | diff --git a/packages/extra/ingress/templates/cdi-uploadproxy.yaml b/packages/extra/ingress/templates/cdi-uploadproxy.yaml deleted file mode 100644 index e82e0d26..00000000 --- a/packages/extra/ingress/templates/cdi-uploadproxy.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} - -{{- if .Values.cdiUploadProxy }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/backend-protocol: HTTPS - cert-manager.io/cluster-issuer: letsencrypt-prod - {{- if eq $issuerType "cloudflare" }} - {{- else }} - acme.cert-manager.io/http01-ingress-class: {{ .Release.Namespace }} - {{- end }} - name: cdi-uploadproxy-{{ .Release.Namespace }} - namespace: cozy-kubevirt-cdi -spec: - ingressClassName: {{ .Release.Namespace }} - rules: - - host: cdi-uploadproxy.{{ $host }} - http: - paths: - - backend: - service: - name: cdi-uploadproxy - port: - number: 443 - path: / - pathType: Prefix - tls: - - hosts: - - cdi-uploadproxy.{{ $host }} - secretName: cdi-uploadproxy-{{ .Release.Namespace }}-tls -{{- end }} diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index d0b67be4..88d98b74 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,3 +1,6 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $exposeExternalIPs := (index $cozyConfig.data "expose-external-ips") | default "" }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -11,7 +14,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system - version: '*' + version: '>= 0.0.0-0' interval: 1m0s timeout: 5m0s values: @@ -31,9 +34,9 @@ spec: enabled: false {{- end }} service: - {{- if .Values.externalIPs }} + {{- if and (eq $exposeIngress .Release.Namespace) $exposeExternalIPs }} externalIPs: - {{- toYaml .Values.externalIPs | nindent 12 }} + {{- toYaml (splitList "," $exposeExternalIPs) | nindent 12 }} type: ClusterIP externalTrafficPolicy: Cluster {{- else }} diff --git a/packages/extra/ingress/values.schema.json b/packages/extra/ingress/values.schema.json index 8005ac24..c956bac3 100644 --- a/packages/extra/ingress/values.schema.json +++ b/packages/extra/ingress/values.schema.json @@ -25,21 +25,6 @@ "type": "boolean", "description": "Restoring original visitor IPs when Cloudflare proxied is enabled", "default": false - }, - "dashboard": { - "type": "boolean", - "description": "Should ingress serve Cozystack service dashboard", - "default": false - }, - "cdiUploadProxy": { - "type": "boolean", - "description": "Should ingress serve CDI upload proxy", - "default": false - }, - "virtExportProxy": { - "type": "boolean", - "description": "Should ingress serve KubeVirt export proxy", - "default": false } } } \ No newline at end of file diff --git a/packages/extra/ingress/values.yaml b/packages/extra/ingress/values.yaml index 41571db9..a5cee834 100644 --- a/packages/extra/ingress/values.yaml +++ b/packages/extra/ingress/values.yaml @@ -4,17 +4,6 @@ ## replicas: 2 -## @param externalIPs [array] List of externalIPs for service. -## Optional. If not specified will use LoadBalancer service by default. -## -## e.g: -## externalIPs: -## - "11.22.33.44" -## - "11.22.33.45" -## - "11.22.33.46" -## -externalIPs: [] - ## @param whitelist List of client networks ## Example: ## whitelist: @@ -24,12 +13,3 @@ whitelist: [] ## @param clouflareProxy Restoring original visitor IPs when Cloudflare proxied is enabled clouflareProxy: false - -## @param dashboard Should ingress serve Cozystack service dashboard -dashboard: false - -## @param cdiUploadProxy Should ingress serve CDI upload proxy -cdiUploadProxy: false - -## @param virtExportProxy Should ingress serve KubeVirt export proxy -virtExportProxy: false diff --git a/packages/extra/ingress/vm-exportproxy.yaml b/packages/extra/ingress/vm-exportproxy.yaml deleted file mode 100644 index 0984bf6c..00000000 --- a/packages/extra/ingress/vm-exportproxy.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} - -{{- if .Values.virtExportProxy }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/backend-protocol: HTTPS - cert-manager.io/cluster-issuer: letsencrypt-prod - {{- if eq $issuerType "cloudflare" }} - {{- else }} - acme.cert-manager.io/http01-ingress-class: {{ .Release.Namespace }} - {{- end }} - name: virt-exportproxy-{{ .Release.Namespace }} - namespace: cozy-kubevirt -spec: - ingressClassName: {{ .Release.Namespace }} - rules: - - host: virt-exportproxy.{{ $host }} - http: - paths: - - backend: - service: - name: virt-exportproxy - port: - number: 443 - path: / - pathType: ImplementationSpecific - tls: - - hosts: - virt-exportproxy.{{ $host }} - secretName: virt-exportproxy-{{ .Release.Namespace }}-tls -{{- end }} diff --git a/packages/extra/monitoring/Makefile b/packages/extra/monitoring/Makefile index dd5b4386..e2b8d330 100644 --- a/packages/extra/monitoring/Makefile +++ b/packages/extra/monitoring/Makefile @@ -13,8 +13,10 @@ generate: rm -f values.schema.json.tmp image: - docker buildx build --platform linux/amd64 images/grafana \ + docker buildx build images/grafana \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/grafana:$(call settag,$(GRAFANA_TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/grafana:latest \ --cache-to type=inline \ diff --git a/packages/extra/monitoring/images/grafana.tag b/packages/extra/monitoring/images/grafana.tag index 73fca310..e22b556a 100644 --- a/packages/extra/monitoring/images/grafana.tag +++ b/packages/extra/monitoring/images/grafana.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/grafana:1.9.2@sha256:c63978e1ed0304e8518b31ddee56c4e8115541b997d8efbe1c0a74da57140399 +ghcr.io/cozystack/cozystack/grafana:1.9.2@sha256:24382d445bf7a39ed988ef4dc7a0d9f084db891fcb5f42fd2e64622710b9457e diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index b9846aa1..a2fcb30c 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -14,7 +14,7 @@ spec: kind: HelmRepository name: cozystack-system namespace: cozy-system - version: '*' + version: '>= 0.0.0-0' interval: 1m0s timeout: 5m0s values: diff --git a/packages/extra/versions_map b/packages/extra/versions_map index 289b0cfe..a7accda5 100644 --- a/packages/extra/versions_map +++ b/packages/extra/versions_map @@ -11,13 +11,15 @@ etcd 2.5.0 24fa7222 etcd 2.6.0 8c460528 etcd 2.6.1 45a7416c etcd 2.7.0 HEAD -info 1.0.0 HEAD +info 1.0.0 93bdf411 +info 1.0.1 HEAD ingress 1.0.0 d7cfa53c ingress 1.1.0 5bbc488e ingress 1.2.0 28fca4ef ingress 1.3.0 fde4bcfa ingress 1.4.0 fd240701 -ingress 1.5.0 HEAD +ingress 1.5.0 93bdf411 +ingress 1.6.0 HEAD monitoring 1.0.0 d7cfa53c monitoring 1.1.0 25221fdc monitoring 1.2.0 f81be075 diff --git a/packages/library/Makefile b/packages/library/Makefile new file mode 100644 index 00000000..42651d03 --- /dev/null +++ b/packages/library/Makefile @@ -0,0 +1,8 @@ +OUT=../_out/repos/library +TMP := $(shell mktemp -d) + +repo: + cd .. && ../hack/package_chart.sh library $(OUT) $(TMP) + +fix-chartnames: + find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i "s/^name: .*/name: $$i/" "$$i/Chart.yaml"; done diff --git a/packages/library/cozy-lib/.helmignore b/packages/library/cozy-lib/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/library/cozy-lib/.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/packages/library/cozy-lib/Chart.yaml b/packages/library/cozy-lib/Chart.yaml new file mode 100644 index 00000000..81a3634d --- /dev/null +++ b/packages/library/cozy-lib/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: cozy-lib +description: Common Cozystack templates + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: library + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 diff --git a/packages/library/cozy-lib/Makefile b/packages/library/cozy-lib/Makefile new file mode 100644 index 00000000..fa0142de --- /dev/null +++ b/packages/library/cozy-lib/Makefile @@ -0,0 +1,6 @@ +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk + +generate: + readme-generator -v values.yaml -s values.schema.json -r README.md + diff --git a/packages/library/cozy-lib/README.md b/packages/library/cozy-lib/README.md new file mode 100644 index 00000000..d4bf18ad --- /dev/null +++ b/packages/library/cozy-lib/README.md @@ -0,0 +1 @@ +## Parameters diff --git a/packages/library/cozy-lib/templates/_resourcepresets.tpl b/packages/library/cozy-lib/templates/_resourcepresets.tpl new file mode 100644 index 00000000..f6ecef3f --- /dev/null +++ b/packages/library/cozy-lib/templates/_resourcepresets.tpl @@ -0,0 +1,49 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a resource request/limit object based on a given preset. +These presets are for basic testing and not meant to be used in production +{{ include "cozy-lib.resources.preset" "nano" -}} +*/}} +{{- define "cozy-lib.resources.preset" -}} +{{- $presets := dict + "nano" (dict + "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") + ) + "micro" (dict + "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") + ) + "small" (dict + "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") + ) + "medium" (dict + "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") + ) + "large" (dict + "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") + ) + "xlarge" (dict + "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") + ) + "2xlarge" (dict + "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") + "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") + ) + }} +{{- if hasKey $presets . -}} +{{- index $presets . | toYaml -}} +{{- else -}} +{{- printf "ERROR: Preset key '%s' invalid. Allowed values are %s" . (join "," (keys $presets)) | fail -}} +{{- end -}} +{{- end -}} diff --git a/packages/library/cozy-lib/templates/_resources.tpl b/packages/library/cozy-lib/templates/_resources.tpl new file mode 100644 index 00000000..34ed9ca2 --- /dev/null +++ b/packages/library/cozy-lib/templates/_resources.tpl @@ -0,0 +1,53 @@ +{{- /* + A sanitized resource map is a dict with resource-name => resource-quantity. + If not in such a form, requests are used, then limits. All resources are set + to have equal requests and limits, except CPU, that has only requests. The + template expects to receive a dict {"requests":{...}, "limits":{...}} as + input, e.g. {{ include "cozy-lib.resources.sanitize" .Values.resources }}. + Example input: + ============== + limits: + cpu: 100m + memory: 1024Mi + requests: + cpu: 200m + memory: 512Mi + memory: 256Mi + devices.com/nvidia: "1" + + Example output: + =============== + limits: + devices.com/nvidia: "1" + memory: 256Mi + requests: + cpu: 200m + devices.com/nvidia: "1" + memory: 256Mi +*/}} +{{- define "cozy-lib.resources.sanitize" }} +{{- $sanitizedMap := dict }} +{{- if hasKey . "limits" }} +{{- range $k, $v := .limits }} +{{- $_ := set $sanitizedMap $k $v }} +{{- end }} +{{- end }} +{{- if hasKey . "requests" }} +{{- range $k, $v := .requests }} +{{- $_ := set $sanitizedMap $k $v }} +{{- end }} +{{- end }} +{{- range $k, $v := . }} +{{- if not (or (eq $k "requests") (eq $k "limits")) }} +{{- $_ := set $sanitizedMap $k $v }} +{{- end }} +{{- end }} +{{- $output := dict "requests" dict "limits" dict }} +{{- range $k, $v := $sanitizedMap }} +{{- $_ := set $output.requests $k $v }} +{{- if not (eq $k "cpu") }} +{{- $_ := set $output.limits $k $v }} +{{- end }} +{{- end }} +{{- $output | toYaml }} +{{- end }} diff --git a/packages/library/cozy-lib/values.schema.json b/packages/library/cozy-lib/values.schema.json new file mode 100644 index 00000000..decc79aa --- /dev/null +++ b/packages/library/cozy-lib/values.schema.json @@ -0,0 +1,5 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/packages/library/cozy-lib/values.yaml b/packages/library/cozy-lib/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/library/cozy-lib/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/library/testfile b/packages/library/testfile new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/Makefile b/packages/system/Makefile index e40b0bf1..2031c3a0 100644 --- a/packages/system/Makefile +++ b/packages/system/Makefile @@ -5,7 +5,7 @@ include ../../scripts/common-envs.mk repo: rm -rf "$(OUT)" mkdir -p "$(OUT)" - helm package -d "$(OUT)" $$(find . -mindepth 2 -maxdepth 2 -name Chart.yaml | awk 'sub("/Chart.yaml", "")') --version $(VERSION) + helm package -d "$(OUT)" $$(find . -mindepth 2 -maxdepth 2 -name Chart.yaml | awk 'sub("/Chart.yaml", "")') --version $(COZYSTACK_VERSION) cd "$(OUT)" && helm repo index . fix-chartnames: diff --git a/packages/system/bucket/Makefile b/packages/system/bucket/Makefile index 125e2e98..1f8d34b2 100644 --- a/packages/system/bucket/Makefile +++ b/packages/system/bucket/Makefile @@ -6,14 +6,15 @@ include ../../../scripts/common-envs.mk include ../../../scripts/package.mk update: - rm -rf charts - helm pull oci://ghcr.io/aenix-io/charts/etcd-operator --untar --untardir charts + @echo Nothing to update image: image-s3manager image-s3manager: - docker buildx build --platform linux/amd64 --build-arg ARCH=amd64 images/s3manager \ + docker buildx build images/s3manager \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/s3manager:$(call settag,$(S3MANAGER_TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/s3manager:latest \ --cache-to type=inline \ diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 779c0b7d..c384dc90 100644 --- a/packages/system/bucket/images/s3manager.tag +++ b/packages/system/bucket/images/s3manager.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:a47d2743d01bff0ce60aa745fdff54f9b7184dff8679b11ab4ecd08ac663012b +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:4399c240ce1f99660d5d1be9d6d7b3e8157c50e4aba58345d51a1d9ac25779a3 diff --git a/packages/system/bucket/images/s3manager/Dockerfile b/packages/system/bucket/images/s3manager/Dockerfile index de59229a..179acead 100644 --- a/packages/system/bucket/images/s3manager/Dockerfile +++ b/packages/system/bucket/images/s3manager/Dockerfile @@ -1,11 +1,15 @@ # Source: https://github.com/cloudlena/s3manager/blob/main/Dockerfile FROM docker.io/library/golang:1 AS builder + +ARG TARGETOS +ARG TARGETARCH + WORKDIR /usr/src/app RUN wget -O- https://github.com/cloudlena/s3manager/archive/9a7c8e446b422f8973b8c461990f39fdafee9c27.tar.gz | tar -xzf- --strip 1 ADD cozystack.patch / RUN git apply /cozystack.patch -RUN CGO_ENABLED=0 go build -ldflags="-s -w" -a -installsuffix cgo -o bin/s3manager +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-s -w" -a -installsuffix cgo -o bin/s3manager FROM docker.io/library/alpine:latest WORKDIR /usr/src/app diff --git a/packages/system/bucket/values.yaml b/packages/system/bucket/values.yaml index 4b57a59c..e1499c6e 100644 --- a/packages/system/bucket/values.yaml +++ b/packages/system/bucket/values.yaml @@ -1 +1 @@ -bucketName: "" +bucketName: "cozystack" diff --git a/packages/system/capi-operator/Makefile b/packages/system/capi-operator/Makefile index baa4a5fc..dc421cee 100644 --- a/packages/system/capi-operator/Makefile +++ b/packages/system/capi-operator/Makefile @@ -1,11 +1,11 @@ export NAME=capi-operator export NAMESPACE=cozy-cluster-api +export REPO_NAME=capi-operator +export REPO_URL=https://kubernetes-sigs.github.io/cluster-api-operator +export CHART_NAME=cluster-api-operator +export CHART_VERSION=^0.19 include ../../../scripts/package.mk -update: - rm -rf charts - helm repo add capi-operator https://kubernetes-sigs.github.io/cluster-api-operator - helm repo update capi-operator - helm pull capi-operator/cluster-api-operator --untar --untardir charts - rm -rf charts/cluster-api-operator/charts +update: clean capi-operator-update + rm -rf charts/cluster-api-operator/charts/ diff --git a/packages/system/capi-operator/charts/cluster-api-operator/Chart.yaml b/packages/system/capi-operator/charts/cluster-api-operator/Chart.yaml index 5108c7dc..323a3594 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/Chart.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -appVersion: 0.18.1 +appVersion: 0.19.0 description: Cluster API Operator name: cluster-api-operator type: application -version: 0.18.1 +version: 0.19.0 diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/addon.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/addon.yaml index a2eb8fb9..6a341496 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/addon.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/addon.yaml @@ -1,26 +1,8 @@ # Addon provider -{{- if .Values.addon }} -{{- $addons := split ";" .Values.addon }} -{{- $addonNamespace := "" }} -{{- $addonName := "" }} -{{- $addonVersion := "" }} -{{- range $addon := $addons }} -{{- $addonArgs := split ":" $addon }} -{{- $addonArgsLen := len $addonArgs }} -{{- if eq $addonArgsLen 3 }} - {{- $addonNamespace = $addonArgs._0 }} - {{- $addonName = $addonArgs._1 }} - {{- $addonVersion = $addonArgs._2 }} -{{- else if eq $addonArgsLen 2 }} - {{- $addonNamespace = print $addonArgs._0 "-addon-system" }} - {{- $addonName = $addonArgs._0 }} - {{- $addonVersion = $addonArgs._1 }} -{{- else if eq $addonArgsLen 1 }} - {{- $addonNamespace = print $addonArgs._0 "-addon-system" }} - {{- $addonName = $addonArgs._0 }} -{{- else }} - {{- fail "addon provider argument should have the following format helm:v1.0.0 or mynamespace:helm:v1.0.0" }} -{{- end }} +{{- range $name, $addon := $.Values.addon }} + {{- $addonNamespace := default ( printf "%s-%s" $name "addon-system" ) (get $addon "namespace") }} + {{- $addonName := $name }} + {{- $addonVersion := get $addon "version" }} --- apiVersion: v1 kind: Namespace @@ -56,5 +38,24 @@ spec: {{- if $.Values.secretNamespace }} secretNamespace: {{ $.Values.secretNamespace }} {{- end }} +{{- if $addon.manifestPatches }} + manifestPatches: {{ toYaml $addon.manifestPatches | nindent 4 }} {{- end }} +{{- if $addon.additionalManifests }} + additionalManifests: + name: {{ $addon.additionalManifests.name }} + {{- if $addon.additionalManifests.namespace }} + namespace: {{ $addon.additionalManifests.namespace }} + {{- end }} {{/* if $addon.additionalManifests.namespace */}} {{- end }} +{{- if $addon.additionalManifests }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $addon.additionalManifests.name }} + namespace: {{ default $addonNamespace $addon.additionalManifests.namespace }} +data: + manifests: {{- toYaml $addon.additionalManifests.manifests | nindent 4 }} +{{- end }} +{{- end }} {{/* range $name, $addon := .Values.addon */}} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/bootstrap.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/bootstrap.yaml index ed5d7924..78dad47e 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/bootstrap.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/bootstrap.yaml @@ -1,26 +1,8 @@ # Bootstrap provider -{{- if .Values.bootstrap }} -{{- $bootstraps := split ";" .Values.bootstrap }} -{{- $bootstrapNamespace := "" }} -{{- $bootstrapName := "" }} -{{- $bootstrapVersion := "" }} -{{- range $bootstrap := $bootstraps }} -{{- $bootstrapArgs := split ":" $bootstrap }} -{{- $bootstrapArgsLen := len $bootstrapArgs }} -{{- if eq $bootstrapArgsLen 3 }} - {{- $bootstrapNamespace = $bootstrapArgs._0 }} - {{- $bootstrapName = $bootstrapArgs._1 }} - {{- $bootstrapVersion = $bootstrapArgs._2 }} -{{- else if eq $bootstrapArgsLen 2 }} - {{- $bootstrapNamespace = print $bootstrapArgs._0 "-bootstrap-system" }} - {{- $bootstrapName = $bootstrapArgs._0 }} - {{- $bootstrapVersion = $bootstrapArgs._1 }} -{{- else if eq $bootstrapArgsLen 1 }} - {{- $bootstrapNamespace = print $bootstrapArgs._0 "-bootstrap-system" }} - {{- $bootstrapName = $bootstrapArgs._0 }} -{{- else }} - {{- fail "bootstrap provider argument should have the following format kubeadm:v1.0.0 or mynamespace:kubeadm:v1.0.0" }} -{{- end }} +{{- range $name, $bootstrap := $.Values.bootstrap }} + {{- $bootstrapNamespace := default ( printf "%s-%s" $name "bootstrap-system" ) (get $bootstrap "namespace") }} + {{- $bootstrapName := $name }} + {{- $bootstrapVersion := get $bootstrap "version" }} --- apiVersion: v1 kind: Namespace @@ -57,5 +39,24 @@ spec: namespace: {{ $.Values.configSecret.namespace }} {{- end }} {{- end }} +{{- if $bootstrap.manifestPatches }} + manifestPatches: {{ toYaml $bootstrap.manifestPatches | nindent 4 }} {{- end }} +{{- if $bootstrap.additionalManifests }} + additionalManifests: + name: {{ $bootstrap.additionalManifests.name }} + {{- if $bootstrap.additionalManifests.namespace }} + namespace: {{ $bootstrap.additionalManifests.namespace }} + {{- end }} {{/* if $bootstrap.additionalManifests.namespace */}} {{- end }} +{{- if $bootstrap.additionalManifests }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $bootstrap.additionalManifests.name }} + namespace: {{ default $bootstrapNamespace $bootstrap.additionalManifests.namespace }} +data: + manifests: {{- toYaml $bootstrap.additionalManifests.manifests | nindent 4 }} +{{- end }} +{{- end }} {{/* range $name, $bootstrap := .Values.bootstrap */}} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/control-plane.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/control-plane.yaml index d72249d1..8a020afd 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/control-plane.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/control-plane.yaml @@ -1,26 +1,8 @@ # Control plane provider -{{- if .Values.controlPlane }} -{{- $controlPlanes := split ";" .Values.controlPlane }} -{{- $controlPlaneNamespace := "" }} -{{- $controlPlaneName := "" }} -{{- $controlPlaneVersion := "" }} -{{- range $controlPlane := $controlPlanes }} -{{- $controlPlaneArgs := split ":" $controlPlane }} -{{- $controlPlaneArgsLen := len $controlPlaneArgs }} -{{- if eq $controlPlaneArgsLen 3 }} - {{- $controlPlaneNamespace = $controlPlaneArgs._0 }} - {{- $controlPlaneName = $controlPlaneArgs._1 }} - {{- $controlPlaneVersion = $controlPlaneArgs._2 }} -{{- else if eq $controlPlaneArgsLen 2 }} - {{- $controlPlaneNamespace = print $controlPlaneArgs._0 "-control-plane-system" }} - {{- $controlPlaneName = $controlPlaneArgs._0 }} - {{- $controlPlaneVersion = $controlPlaneArgs._1 }} -{{- else if eq $controlPlaneArgsLen 1 }} - {{- $controlPlaneNamespace = print $controlPlaneArgs._0 "-control-plane-system" }} - {{- $controlPlaneName = $controlPlaneArgs._0 }} -{{- else }} - {{- fail "controlplane provider argument should have the following format kubeadm:v1.0.0 or mynamespace:kubeadm:v1.0.0" }} -{{- end }} +{{- range $name, $controlPlane := $.Values.controlPlane }} + {{- $controlPlaneNamespace := default ( printf "%s-%s" $name "control-plane-system" ) (get $controlPlane "namespace") }} + {{- $controlPlaneName := $name }} + {{- $controlPlaneVersion := get $controlPlane "version" }} --- apiVersion: v1 kind: Namespace @@ -70,5 +52,24 @@ spec: namespace: {{ $.Values.configSecret.namespace }} {{- end }} {{- end }} +{{- if $controlPlane.manifestPatches }} + manifestPatches: {{ toYaml $controlPlane.manifestPatches | nindent 4 }} {{- end }} +{{- if $controlPlane.additionalManifests }} + additionalManifests: + name: {{ $controlPlane.additionalManifests.name }} + {{- if $controlPlane.additionalManifests.namespace }} + namespace: {{ $controlPlane.additionalManifests.namespace }} + {{- end }} {{/* if $controlPlane.additionalManifests.namespace */}} {{- end }} +{{- if $controlPlane.additionalManifests }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $controlPlane.additionalManifests.name }} + namespace: {{ default $controlPlaneNamespace $controlPlane.additionalManifests.namespace }} +data: + manifests: {{- toYaml $controlPlane.additionalManifests.manifests | nindent 4 }} +{{- end }} +{{- end }} {{/* range $name, $controlPlane := .Values.controlPlane */}} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/core.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/core.yaml index 828d2269..648e1b60 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/core.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/core.yaml @@ -1,25 +1,8 @@ # Core provider -{{- if .Values.core }} -{{- $coreArgs := split ":" .Values.core }} -{{- $coreArgsLen := len $coreArgs }} -{{- $coreVersion := "" }} -{{- $coreNamespace := "" }} -{{- $coreName := "" }} -{{- $coreVersion := "" }} -{{- if eq $coreArgsLen 3 }} - {{- $coreNamespace = $coreArgs._0 }} - {{- $coreName = $coreArgs._1 }} - {{- $coreVersion = $coreArgs._2 }} -{{- else if eq $coreArgsLen 2 }} - {{- $coreNamespace = "capi-system" }} - {{- $coreName = $coreArgs._0 }} - {{- $coreVersion = $coreArgs._1 }} -{{- else if eq $coreArgsLen 1 }} - {{- $coreNamespace = "capi-system" }} - {{- $coreName = $coreArgs._0 }} -{{- else }} - {{- fail "core provider argument should have the following format cluster-api:v1.0.0 or mynamespace:cluster-api:v1.0.0" }} -{{- end }} +{{- range $name, $core := $.Values.core }} + {{- $coreNamespace := default "capi-system" (get $core "namespace") }} + {{- $coreName := $name }} + {{- $coreVersion := get $core "version" }} --- apiVersion: v1 kind: Namespace @@ -65,4 +48,24 @@ spec: namespace: {{ $.Values.configSecret.namespace }} {{- end }} {{- end }} +{{- if $core.manifestPatches }} + manifestPatches: {{ toYaml $core.manifestPatches | nindent 4 }} {{- end }} +{{- if $core.additionalManifests }} + additionalManifests: + name: {{ $core.additionalManifests.name }} + {{- if $core.additionalManifests.namespace }} + namespace: {{ $core.additionalManifests.namespace }} + {{- end }} +{{- end }} +{{- if $core.additionalManifests }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $core.additionalManifests.name }} + namespace: {{ default $coreNamespace $core.additionalManifests.namespace }} +data: + manifests: {{- toYaml $core.additionalManifests.manifests | nindent 4 }} +{{- end }} +{{- end }} {{/* range $name, $core := .Values.core */}} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/infra.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/infra.yaml index 5841336c..835607d4 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/infra.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/infra.yaml @@ -1,26 +1,8 @@ # Infrastructure providers -{{- if .Values.infrastructure }} -{{- $infrastructures := split ";" .Values.infrastructure }} -{{- $infrastructureNamespace := "" }} -{{- $infrastructureName := "" }} -{{- $infrastructureVersion := "" }} -{{- range $infrastructure := $infrastructures }} -{{- $infrastructureArgs := split ":" $infrastructure }} -{{- $infrastructureArgsLen := len $infrastructureArgs }} -{{- if eq $infrastructureArgsLen 3 }} - {{- $infrastructureNamespace = $infrastructureArgs._0 }} - {{- $infrastructureName = $infrastructureArgs._1 }} - {{- $infrastructureVersion = $infrastructureArgs._2 }} -{{- else if eq $infrastructureArgsLen 2 }} - {{- $infrastructureNamespace = print $infrastructureArgs._0 "-infrastructure-system" }} - {{- $infrastructureName = $infrastructureArgs._0 }} - {{- $infrastructureVersion = $infrastructureArgs._1 }} -{{- else if eq $infrastructureArgsLen 1 }} - {{- $infrastructureNamespace = print $infrastructureArgs._0 "-infrastructure-system" }} - {{- $infrastructureName = $infrastructureArgs._0 }} -{{- else }} - {{- fail "infrastructure provider argument should have the following format aws:v1.0.0 or mynamespace:aws:v1.0.0" }} -{{- end }} +{{- range $name, $infra := $.Values.infrastructure }} + {{- $infrastructureNamespace := default ( printf "%s-%s" $name "infrastructure-system" ) (get $infra "namespace") }} + {{- $infrastructureName := $name }} + {{- $infrastructureVersion := get $infra "version" }} --- apiVersion: v1 kind: Namespace @@ -83,5 +65,24 @@ spec: {{- if $.Values.additionalDeployments }} additionalDeployments: {{ toYaml $.Values.additionalDeployments | nindent 4 }} {{- end }} +{{- if $infra.manifestPatches }} + manifestPatches: {{- toYaml $infra.manifestPatches | nindent 4 }} +{{- end }} {{/* if $infra.manifestPatches */}} +{{- if $infra.additionalManifests }} + additionalManifests: + name: {{ $infra.additionalManifests.name }} + {{- if $infra.additionalManifests.namespace }} + namespace: {{ $infra.additionalManifests.namespace }} + {{- end }} {{/* if $infra.additionalManifests.namespace */}} +{{- end }} {{/* if $infra.additionalManifests */}} +{{- if $infra.additionalManifests }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $infra.additionalManifests.name }} + namespace: {{ default $infrastructureNamespace $infra.additionalManifests.namespace }} +data: + manifests: {{- toYaml $infra.additionalManifests.manifests | nindent 4 }} {{- end }} -{{- end }} +{{- end }} {{/* range $name, $infra := .Values.infrastructure */}} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/ipam.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/ipam.yaml index 06960afb..4a33c42f 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/ipam.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/ipam.yaml @@ -1,26 +1,8 @@ # IPAM providers -{{- if .Values.ipam }} -{{- $ipams := split ";" .Values.ipam }} -{{- $ipamNamespace := "" }} -{{- $ipamName := "" }} -{{- $ipamVersion := "" }} -{{- range $ipam := $ipams }} -{{- $ipamArgs := split ":" $ipam }} -{{- $ipamArgsLen := len $ipamArgs }} -{{- if eq $ipamArgsLen 3 }} - {{- $ipamNamespace = $ipamArgs._0 }} - {{- $ipamName = $ipamArgs._1 }} - {{- $ipamVersion = $ipamArgs._2 }} -{{- else if eq $ipamArgsLen 2 }} - {{- $ipamNamespace = print $ipamArgs._0 "-ipam-system" }} - {{- $ipamName = $ipamArgs._0 }} - {{- $ipamVersion = $ipamArgs._1 }} -{{- else if eq $ipamArgsLen 1 }} - {{- $ipamNamespace = print $ipamArgs._0 "-ipam-system" }} - {{- $ipamName = $ipamArgs._0 }} -{{- else }} - {{- fail "ipam provider argument should have the following format in-cluster:v1.0.0 or mynamespace:in-cluster:v1.0.0" }} -{{- end }} +{{- range $name, $ipam := $.Values.ipam }} + {{- $ipamNamespace := default ( printf "%s-%s" $name "ipam-system" ) (get $ipam "namespace") }} + {{- $ipamName := $name }} + {{- $ipamVersion := get $ipam "version" }} --- apiVersion: v1 kind: Namespace @@ -70,8 +52,27 @@ spec: namespace: {{ $.Values.configSecret.namespace }} {{- end }} {{- end }} +{{- if $ipam.manifestPatches }} + manifestPatches: {{ toYaml $ipam.manifestPatches | nindent 4 }} +{{- end }} {{- if $.Values.additionalDeployments }} additionalDeployments: {{ toYaml $.Values.additionalDeployments | nindent 4 }} {{- end }} +{{- if $ipam.additionalManifests }} + additionalManifests: + name: {{ $ipam.additionalManifests.name }} + {{- if $ipam.additionalManifests.namespace }} + namespace: {{ $ipam.additionalManifests.namespace }} + {{- end }} {{/* if $ipam.additionalManifests.namespace */}} {{- end }} +{{- if $ipam.additionalManifests }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $ipam.additionalManifests.name }} + namespace: {{ default $ipamNamespace $ipam.additionalManifests.namespace }} +data: + manifests: {{- toYaml $ipam.additionalManifests.manifests | nindent 4 }} {{- end }} +{{- end }} {{/* range $name, $ipam := .Values.ipam */}} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/templates/operator-components.yaml b/packages/system/capi-operator/charts/cluster-api-operator/templates/operator-components.yaml index 27b8bf80..0ee82bfc 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/templates/operator-components.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/templates/operator-components.yaml @@ -1305,6 +1305,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -2836,6 +2843,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -3048,27 +3062,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -3078,6 +3097,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -4711,27 +4732,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -4741,6 +4767,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -6043,6 +6071,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -7574,6 +7609,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -7786,27 +7828,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -7816,6 +7863,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -9450,27 +9499,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -9480,6 +9534,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -10783,6 +10839,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -12314,6 +12377,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -12527,27 +12597,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -12557,6 +12632,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -14190,27 +14267,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -14220,6 +14302,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -15522,6 +15606,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -17053,6 +17144,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -17265,27 +17363,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -17295,6 +17398,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -18929,27 +19034,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -18959,6 +19069,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -20262,6 +20374,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -21793,6 +21912,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -22006,27 +22132,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -22036,6 +22167,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -23371,6 +23504,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -24902,6 +25042,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -25114,27 +25261,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -25144,6 +25296,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime @@ -26481,6 +26635,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the additional provider deployment. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -28012,6 +28173,13 @@ spec: description: Manager defines the properties that can be enabled on the controller manager for the provider. properties: + additionalArgs: + additionalProperties: + type: string + description: |- + AdditionalArgs is a map of additional options that will be passed + in as container args to the provider's controller manager. + type: object cacheNamespace: description: |- CacheNamespace if specified restricts the manager's cache to watch objects in @@ -28225,27 +28393,32 @@ spec: properties: lastTransitionTime: description: |- - Last time the condition transitioned from one status to another. + lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - A human readable message indicating details about the transition. + message is a human readable message indicating details about the transition. This field may be empty. + maxLength: 10240 + minLength: 1 type: string reason: description: |- - The reason for the condition's last transition in CamelCase. + reason is the reason for the condition's last transition in CamelCase. The specific API may choose whether or not this field is considered a guaranteed API. This field may be empty. + maxLength: 256 + minLength: 1 type: string severity: description: |- severity provides an explicit classification of Reason code, so the users or machines can immediately understand the current situation and act accordingly. The Severity field MUST be set only when Status=False. + maxLength: 32 type: string status: description: status of the condition, one of True, False, Unknown. @@ -28255,6 +28428,8 @@ spec: type of condition in CamelCase or in foo.example.com/CamelCase. Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 type: string required: - lastTransitionTime diff --git a/packages/system/capi-operator/charts/cluster-api-operator/values.schema.json b/packages/system/capi-operator/charts/cluster-api-operator/values.schema.json new file mode 100644 index 00000000..d22038fc --- /dev/null +++ b/packages/system/capi-operator/charts/cluster-api-operator/values.schema.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "core": { + "oneOf": [ + { "type": "object" }, + { "type": "null" } + ] + }, + "bootstrap": { + "type": "object", + "oneOf": [ + { "type": "object" }, + { "type": "null" } + ] + }, + "controlPlane": { + "type": "object", + "oneOf": [ + { "type": "object" }, + { "type": "null" } + ] + }, + "infrastructure": { + "type": "object", + "oneOf": [ + { "type": "object" }, + { "type": "null" } + ] + }, + "addon": { + "type": "object", + "oneOf": [ + { "type": "object" }, + { "type": "null" } + ] + }, + "ipam": { + "type": "object", + "oneOf": [ + { "type": "object" }, + { "type": "null" } + ] + } + } +} diff --git a/packages/system/capi-operator/charts/cluster-api-operator/values.yaml b/packages/system/capi-operator/charts/cluster-api-operator/values.yaml index 12507a3c..545bae39 100644 --- a/packages/system/capi-operator/charts/cluster-api-operator/values.yaml +++ b/packages/system/capi-operator/charts/cluster-api-operator/values.yaml @@ -1,12 +1,30 @@ --- # --- # Cluster API provider options -core: "" -bootstrap: "" -controlPlane: "" -infrastructure: "" -ipam: "" -addon: "" +core: {} +# cluster-api: {} # Name, required +# namespace: "" # Optional +# version: "" # Optional +bootstrap: {} +# kubeadm: {} # Name, required +# namespace: "" # Optional +# version: "" # Optional +controlPlane: {} +# kubeadm: {} # Name, required +# namespace: "" # Optional +# version: "" # Optional +infrastructure: {} +# docker: {} # Name, required +# namespace: "" # Optional +# version: "" # Optional +addon: {} +# helm: {} # Name, required +# namespace: "" # Optional +# version: "" # Optional +ipam: {} +# in-cluster: {} # Name, required +# namespace: "" # Optional +# version: "" # Optional manager.featureGates: {} fetchConfig: {} # --- @@ -21,7 +39,7 @@ leaderElection: image: manager: repository: registry.k8s.io/capi-operator/cluster-api-operator - tag: v0.18.1 + tag: v0.19.0 pullPolicy: IfNotPresent env: manager: [] diff --git a/packages/system/capi-providers/templates/providers.yaml b/packages/system/capi-providers/templates/providers.yaml index 5c3b1e54..b2accf40 100644 --- a/packages/system/capi-providers/templates/providers.yaml +++ b/packages/system/capi-providers/templates/providers.yaml @@ -5,7 +5,7 @@ metadata: name: cluster-api spec: # https://github.com/kubernetes-sigs/cluster-api - version: v1.9.5 + version: v1.10.1 --- apiVersion: operator.cluster.x-k8s.io/v1alpha2 kind: ControlPlaneProvider @@ -13,7 +13,7 @@ metadata: name: kamaji spec: # https://github.com/clastix/cluster-api-control-plane-provider-kamaji - version: v0.14.1 + version: v0.15.1 deployment: containers: - name: manager @@ -31,7 +31,7 @@ metadata: name: kubeadm spec: # https://github.com/kubernetes-sigs/cluster-api - version: v1.9.5 + version: v1.10.1 --- apiVersion: operator.cluster.x-k8s.io/v1alpha2 kind: InfrastructureProvider @@ -39,26 +39,4 @@ metadata: name: kubevirt spec: # https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt - version: v0.1.9 - -{{- if .Values.providers.proxmox }} ---- -apiVersion: operator.cluster.x-k8s.io/v1alpha2 -kind: InfrastructureProvider -metadata: - name: proxmox -spec: - # https://github.com/ionos-cloud/cluster-api-provider-proxmox - version: v0.8.0 -{{- end }} - -{{- if .Values.providers.hetzner }} ---- -apiVersion: operator.cluster.x-k8s.io/v1alpha2 -kind: InfrastructureProvider -metadata: - name: hetzner -spec: - # https://github.com/syself/cluster-api-provider-hetzner - version: v1.0.3 -{{- end }} + version: v0.1.10 diff --git a/packages/system/cert-manager/charts/cert-manager/Chart.yaml b/packages/system/cert-manager/charts/cert-manager/Chart.yaml index 300db669..2a49d00c 100644 --- a/packages/system/cert-manager/charts/cert-manager/Chart.yaml +++ b/packages/system/cert-manager/charts/cert-manager/Chart.yaml @@ -6,7 +6,7 @@ annotations: fingerprint: 1020CF3C033D4F35BAE1C19E1226061C665DF13E url: https://cert-manager.io/public-keys/cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg apiVersion: v2 -appVersion: v1.16.3 +appVersion: v1.17.2 description: A Helm chart for cert-manager home: https://cert-manager.io icon: https://raw.githubusercontent.com/cert-manager/community/4d35a69437d21b76322157e6284be4cd64e6d2b7/logo/logo-small.png @@ -23,4 +23,4 @@ maintainers: name: cert-manager sources: - https://github.com/cert-manager/cert-manager -version: v1.16.3 +version: v1.17.2 diff --git a/packages/system/cert-manager/charts/cert-manager/README.md b/packages/system/cert-manager/charts/cert-manager/README.md index 6fa25cc9..1d502429 100644 --- a/packages/system/cert-manager/charts/cert-manager/README.md +++ b/packages/system/cert-manager/charts/cert-manager/README.md @@ -19,7 +19,7 @@ Before installing the chart, you must first install the cert-manager CustomResou This is performed in a separate step to allow you to easily uninstall and reinstall cert-manager without deleting your installed custom resources. ```bash -$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.3/cert-manager.crds.yaml +$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.crds.yaml ``` To install the chart with the release name `cert-manager`: @@ -29,7 +29,7 @@ To install the chart with the release name `cert-manager`: $ helm repo add jetstack https://charts.jetstack.io --force-update ## Install the cert-manager helm chart -$ helm install cert-manager --namespace cert-manager --version v1.16.3 jetstack/cert-manager +$ helm install cert-manager --namespace cert-manager --version v1.17.2 jetstack/cert-manager ``` In order to begin issuing certificates, you will need to set up a ClusterIssuer @@ -65,7 +65,7 @@ If you want to completely uninstall cert-manager from your cluster, you will als delete the previously installed CustomResourceDefinition resources: ```console -$ kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.3/cert-manager.crds.yaml +$ kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.crds.yaml ``` ## Configuration @@ -316,7 +316,13 @@ If not set and create is true, a name is generated using the fullname template. #### **serviceAccount.annotations** ~ `object` -Optional additional annotations to add to the controller's Service Account. +Optional additional annotations to add to the controller's Service Account. Templates are allowed for both keys and values. +Example using templating: + +```yaml +annotations: + "{{ .Chart.Name }}-helm-chart/version": "{{ .Chart.Version }}" +``` #### **serviceAccount.labels** ~ `object` @@ -364,17 +370,24 @@ config: kubernetesAPIQPS: 9000 kubernetesAPIBurst: 9000 numberOfConcurrentWorkers: 200 + enableGatewayAPI: true + # Feature gates as of v1.17.0. Listed with their default values. + # See https://cert-manager.io/docs/cli/controller/ featureGates: - AdditionalCertificateOutputFormats: true - DisallowInsecureCSRUsageDefinition: true - ExperimentalCertificateSigningRequestControllers: true - ExperimentalGatewayAPISupport: true - LiteralCertificateSubject: true - SecretsFilteredCaching: true - ServerSideApply: true - StableCertificateRequestName: true - UseCertificateRequestBasicConstraints: true - ValidateCAA: true + AdditionalCertificateOutputFormats: true # BETA - default=true + AllAlpha: false # ALPHA - default=false + AllBeta: false # BETA - default=false + ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false + ExperimentalGatewayAPISupport: true # BETA - default=true + LiteralCertificateSubject: true # BETA - default=true + NameConstraints: true # BETA - default=true + OtherNames: false # ALPHA - default=false + SecretsFilteredCaching: true # BETA - default=true + ServerSideApply: false # ALPHA - default=false + StableCertificateRequestName: true # BETA - default=true + UseCertificateRequestBasicConstraints: false # ALPHA - default=false + UseDomainQualifiedFinalizer: true # BETA - default=false + ValidateCAA: false # ALPHA - default=false # Configure the metrics server for TLS # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls metricsTLSConfig: diff --git a/packages/system/cert-manager/charts/cert-manager/templates/cainjector-deployment.yaml b/packages/system/cert-manager/charts/cert-manager/templates/cainjector-deployment.yaml index 65e65894..dc14ab02 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/cainjector-deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/cainjector-deployment.yaml @@ -53,6 +53,12 @@ spec: prometheus.io/port: '9402' {{- end }} spec: + {{- if not .Values.cainjector.serviceAccount.create }} + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} serviceAccountName: {{ template "cainjector.serviceAccountName" . }} {{- if hasKey .Values.cainjector "automountServiceAccountToken" }} automountServiceAccountToken: {{ .Values.cainjector.automountServiceAccountToken }} diff --git a/packages/system/cert-manager/charts/cert-manager/templates/cainjector-service.yaml b/packages/system/cert-manager/charts/cert-manager/templates/cainjector-service.yaml index 2ed9178f..dd0e64db 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/cainjector-service.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/cainjector-service.yaml @@ -1,3 +1,4 @@ +{{- if .Values.cainjector.enabled }} {{- if and .Values.prometheus.enabled (not .Values.prometheus.podmonitor.enabled) }} apiVersion: v1 kind: Service @@ -28,3 +29,4 @@ spec: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: "cainjector" {{- end }} +{{- end }} diff --git a/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml b/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml index 00930f9c..f5f8ec43 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml @@ -514,7 +514,6 @@ spec: type: object required: - create - - passwordSecretRef properties: alias: description: |- @@ -526,17 +525,25 @@ spec: Create enables JKS keystore creation for the Certificate. If true, a file named `keystore.jks` will be created in the target Secret resource, encrypted using the password stored in - `passwordSecretRef`. + `passwordSecretRef` or `password`. The keystore file will be updated immediately. If the issuer provided a CA certificate, a file named `truststore.jks` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority type: boolean + password: + description: |- + Password provides a literal password used to encrypt the JKS keystore. + Mutually exclusive with passwordSecretRef. + One of password or passwordSecretRef must provide a password with a non-zero length. + type: string passwordSecretRef: description: |- - PasswordSecretRef is a reference to a key in a Secret resource + PasswordSecretRef is a reference to a non-empty key in a Secret resource containing the password used to encrypt the JKS keystore. + Mutually exclusive with password. + One of password or passwordSecretRef must provide a password with a non-zero length. type: object required: - name @@ -559,24 +566,31 @@ spec: type: object required: - create - - passwordSecretRef properties: create: description: |- Create enables PKCS12 keystore creation for the Certificate. If true, a file named `keystore.p12` will be created in the target Secret resource, encrypted using the password stored in - `passwordSecretRef`. + `passwordSecretRef` or in `password`. The keystore file will be updated immediately. If the issuer provided a CA certificate, a file named `truststore.p12` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority type: boolean + password: + description: |- + Password provides a literal password used to encrypt the PKCS#12 keystore. + Mutually exclusive with passwordSecretRef. + One of password or passwordSecretRef must provide a password with a non-zero length. + type: string passwordSecretRef: description: |- - PasswordSecretRef is a reference to a key in a Secret resource - containing the password used to encrypt the PKCS12 keystore. + PasswordSecretRef is a reference to a non-empty key in a Secret resource + containing the password used to encrypt the PKCS#12 keystore. + Mutually exclusive with password. + One of password or passwordSecretRef must provide a password with a non-zero length. type: object required: - name @@ -1376,6 +1390,9 @@ spec: resource ID of the managed identity, can not be used at the same time as clientID Cannot be used for Azure Managed Service Identity type: string + tenantID: + description: tenant ID of the managed identity, can not be used at the same time as resourceID + type: string resourceGroupName: description: resource group the DNS zone is located in type: string @@ -4689,6 +4706,9 @@ spec: resource ID of the managed identity, can not be used at the same time as clientID Cannot be used for Azure Managed Service Identity type: string + tenantID: + description: tenant ID of the managed identity, can not be used at the same time as resourceID + type: string resourceGroupName: description: resource group the DNS zone is located in type: string @@ -8415,6 +8435,9 @@ spec: resource ID of the managed identity, can not be used at the same time as clientID Cannot be used for Azure Managed Service Identity type: string + tenantID: + description: tenant ID of the managed identity, can not be used at the same time as resourceID + type: string resourceGroupName: description: resource group the DNS zone is located in type: string diff --git a/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml b/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml index e6f3f681..8a4a9734 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml @@ -52,6 +52,12 @@ spec: prometheus.io/port: '9402' {{- end }} spec: + {{- if not .Values.serviceAccount.create }} + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} serviceAccountName: {{ template "cert-manager.serviceAccountName" . }} {{- if hasKey .Values "automountServiceAccountToken" }} automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} diff --git a/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml b/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml index 87fc00ea..698ddef8 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml @@ -11,7 +11,9 @@ metadata: namespace: {{ include "cert-manager.namespace" . }} {{- with .Values.serviceAccount.annotations }} annotations: - {{- toYaml . | nindent 4 }} + {{- range $k, $v := . }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- end }} {{- end }} labels: app: {{ include "cert-manager.name" . }} diff --git a/packages/system/cert-manager/charts/cert-manager/templates/webhook-deployment.yaml b/packages/system/cert-manager/charts/cert-manager/templates/webhook-deployment.yaml index 1535589f..857cf353 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/webhook-deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/webhook-deployment.yaml @@ -52,6 +52,12 @@ spec: prometheus.io/port: '9402' {{- end }} spec: + {{- if not .Values.webhook.serviceAccount.create }} + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} serviceAccountName: {{ template "webhook.serviceAccountName" . }} {{- if hasKey .Values.webhook "automountServiceAccountToken" }} automountServiceAccountToken: {{ .Values.webhook.automountServiceAccountToken }} diff --git a/packages/system/cert-manager/charts/cert-manager/values.schema.json b/packages/system/cert-manager/charts/cert-manager/values.schema.json index d04da90c..36d1d0ca 100644 --- a/packages/system/cert-manager/charts/cert-manager/values.schema.json +++ b/packages/system/cert-manager/charts/cert-manager/values.schema.json @@ -579,7 +579,7 @@ }, "helm-values.config": { "default": {}, - "description": "This property is used to configure options for the controller pod. This allows setting options that would usually be provided using flags.\n\nIf `apiVersion` and `kind` are unspecified they default to the current latest version (currently `controller.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself.\n\nFor example:\nconfig:\n apiVersion: controller.config.cert-manager.io/v1alpha1\n kind: ControllerConfiguration\n logging:\n verbosity: 2\n format: text\n leaderElectionConfig:\n namespace: kube-system\n kubernetesAPIQPS: 9000\n kubernetesAPIBurst: 9000\n numberOfConcurrentWorkers: 200\n featureGates:\n AdditionalCertificateOutputFormats: true\n DisallowInsecureCSRUsageDefinition: true\n ExperimentalCertificateSigningRequestControllers: true\n ExperimentalGatewayAPISupport: true\n LiteralCertificateSubject: true\n SecretsFilteredCaching: true\n ServerSideApply: true\n StableCertificateRequestName: true\n UseCertificateRequestBasicConstraints: true\n ValidateCAA: true\n # Configure the metrics server for TLS\n # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls\n metricsTLSConfig:\n dynamic:\n secretNamespace: \"cert-manager\"\n secretName: \"cert-manager-metrics-ca\"\n dnsNames:\n - cert-manager-metrics", + "description": "This property is used to configure options for the controller pod. This allows setting options that would usually be provided using flags.\n\nIf `apiVersion` and `kind` are unspecified they default to the current latest version (currently `controller.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself.\n\nFor example:\nconfig:\n apiVersion: controller.config.cert-manager.io/v1alpha1\n kind: ControllerConfiguration\n logging:\n verbosity: 2\n format: text\n leaderElectionConfig:\n namespace: kube-system\n kubernetesAPIQPS: 9000\n kubernetesAPIBurst: 9000\n numberOfConcurrentWorkers: 200\n enableGatewayAPI: true\n # Feature gates as of v1.17.0. Listed with their default values.\n # See https://cert-manager.io/docs/cli/controller/\n featureGates:\n AdditionalCertificateOutputFormats: true # BETA - default=true\n AllAlpha: false # ALPHA - default=false\n AllBeta: false # BETA - default=false\n ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false\n ExperimentalGatewayAPISupport: true # BETA - default=true\n LiteralCertificateSubject: true # BETA - default=true\n NameConstraints: true # BETA - default=true\n OtherNames: false # ALPHA - default=false\n SecretsFilteredCaching: true # BETA - default=true\n ServerSideApply: false # ALPHA - default=false\n StableCertificateRequestName: true # BETA - default=true\n UseCertificateRequestBasicConstraints: false # ALPHA - default=false\n UseDomainQualifiedFinalizer: true # BETA - default=false\n ValidateCAA: false # ALPHA - default=false\n # Configure the metrics server for TLS\n # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls\n metricsTLSConfig:\n dynamic:\n secretNamespace: \"cert-manager\"\n secretName: \"cert-manager-metrics-ca\"\n dnsNames:\n - cert-manager-metrics", "type": "object" }, "helm-values.containerSecurityContext": { @@ -1223,7 +1223,7 @@ "type": "object" }, "helm-values.serviceAccount.annotations": { - "description": "Optional additional annotations to add to the controller's Service Account.", + "description": "Optional additional annotations to add to the controller's Service Account. Templates are allowed for both keys and values.\nExample using templating:\nannotations:\n \"{{ .Chart.Name }}-helm-chart/version\": \"{{ .Chart.Version }}\"", "type": "object" }, "helm-values.serviceAccount.automountServiceAccountToken": { diff --git a/packages/system/cert-manager/charts/cert-manager/values.yaml b/packages/system/cert-manager/charts/cert-manager/values.yaml index 7a1c2953..a8c94f8b 100644 --- a/packages/system/cert-manager/charts/cert-manager/values.yaml +++ b/packages/system/cert-manager/charts/cert-manager/values.yaml @@ -190,7 +190,10 @@ serviceAccount: # +docs:property # name: "" - # Optional additional annotations to add to the controller's Service Account. + # Optional additional annotations to add to the controller's Service Account. Templates are allowed for both keys and values. + # Example using templating: + # annotations: + # "{{ .Chart.Name }}-helm-chart/version": "{{ .Chart.Version }}" # +docs:property # annotations: {} @@ -227,17 +230,24 @@ enableCertificateOwnerRef: false # kubernetesAPIQPS: 9000 # kubernetesAPIBurst: 9000 # numberOfConcurrentWorkers: 200 +# enableGatewayAPI: true +# # Feature gates as of v1.17.0. Listed with their default values. +# # See https://cert-manager.io/docs/cli/controller/ # featureGates: -# AdditionalCertificateOutputFormats: true -# DisallowInsecureCSRUsageDefinition: true -# ExperimentalCertificateSigningRequestControllers: true -# ExperimentalGatewayAPISupport: true -# LiteralCertificateSubject: true -# SecretsFilteredCaching: true -# ServerSideApply: true -# StableCertificateRequestName: true -# UseCertificateRequestBasicConstraints: true -# ValidateCAA: true +# AdditionalCertificateOutputFormats: true # BETA - default=true +# AllAlpha: false # ALPHA - default=false +# AllBeta: false # BETA - default=false +# ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false +# ExperimentalGatewayAPISupport: true # BETA - default=true +# LiteralCertificateSubject: true # BETA - default=true +# NameConstraints: true # BETA - default=true +# OtherNames: false # ALPHA - default=false +# SecretsFilteredCaching: true # BETA - default=true +# ServerSideApply: false # ALPHA - default=false +# StableCertificateRequestName: true # BETA - default=true +# UseCertificateRequestBasicConstraints: false # ALPHA - default=false +# UseDomainQualifiedFinalizer: true # BETA - default=false +# ValidateCAA: false # ALPHA - default=false # # Configure the metrics server for TLS # # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls # metricsTLSConfig: diff --git a/packages/system/cilium/Makefile b/packages/system/cilium/Makefile index e96d20ef..72502d12 100644 --- a/packages/system/cilium/Makefile +++ b/packages/system/cilium/Makefile @@ -18,6 +18,8 @@ update: image: docker buildx build images/cilium \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/cilium:$(call settag,$(CILIUM_TAG)) \ --tag $(REGISTRY)/cilium:$(call settag,$(CILIUM_TAG)-$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/cilium:latest \ diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index 32e14b1d..8e0dea78 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -14,7 +14,7 @@ cilium: mode: "kubernetes" image: repository: ghcr.io/cozystack/cozystack/cilium - tag: 1.17.2 - digest: "sha256:bc6a8ec326188960ac36584873e07801bcbc56cb862e2ec8bf87a7926f66abf1" + tag: 1.17.3 + digest: "sha256:f95e30fd8e7608f61c38344bb9f558f60f4d81bccb8e399836911e4feec2b40a" envoy: enabled: false diff --git a/packages/system/cozystack-api/Makefile b/packages/system/cozystack-api/Makefile index 053fe329..66853833 100644 --- a/packages/system/cozystack-api/Makefile +++ b/packages/system/cozystack-api/Makefile @@ -9,6 +9,8 @@ image: image-cozystack-api image-cozystack-api: docker buildx build -f images/cozystack-api/Dockerfile ../../.. \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/cozystack-api:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/cozystack-api:latest \ --cache-to type=inline \ diff --git a/packages/system/cozystack-api/images/cozystack-api/Dockerfile b/packages/system/cozystack-api/images/cozystack-api/Dockerfile index 6b8e5cc1..c3f90f01 100644 --- a/packages/system/cozystack-api/images/cozystack-api/Dockerfile +++ b/packages/system/cozystack-api/images/cozystack-api/Dockerfile @@ -1,16 +1,19 @@ -FROM golang:1.23-alpine as builder +FROM golang:1.23-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH WORKDIR /workspace COPY go.mod go.sum ./ -RUN go mod download +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download COPY api api/ COPY pkg pkg/ COPY cmd cmd/ COPY internal internal/ -RUN CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /cozystack-api cmd/cozystack-api/main.go +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /cozystack-api cmd/cozystack-api/main.go FROM scratch diff --git a/packages/system/cozystack-api/templates/api-ingress.yaml b/packages/system/cozystack-api/templates/api-ingress.yaml new file mode 100644 index 00000000..d7670e71 --- /dev/null +++ b/packages/system/cozystack-api/templates/api-ingress.yaml @@ -0,0 +1,28 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} +{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} + +{{- if and (has "api" $exposeServices) }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/backend-protocol: HTTPS + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + name: kubernetes + namespace: default +spec: + ingressClassName: {{ $exposeIngress }} + rules: + - host: api.{{ $host }} + http: + paths: + - backend: + service: + name: kubernetes + port: + number: 443 + path: / + pathType: Prefix +{{- end }} diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index a669a153..6f3a84a5 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,2 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.30.2@sha256:7ef370dc8aeac0a6b2a50b7d949f070eb21d267ba0a70e7fc7c1564bfe6d4f83 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.31.0-rc.3@sha256:9940cffabedb510397e3c330887aee724c4d232c011df60f4c16891fcfe1d9bf diff --git a/packages/system/cozystack-controller/Makefile b/packages/system/cozystack-controller/Makefile index a1db9b0a..a75faea9 100644 --- a/packages/system/cozystack-controller/Makefile +++ b/packages/system/cozystack-controller/Makefile @@ -9,6 +9,8 @@ image: image-cozystack-controller update-version image-cozystack-controller: docker buildx build -f images/cozystack-controller/Dockerfile ../../.. \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/cozystack-controller:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/cozystack-controller:latest \ --cache-to type=inline \ diff --git a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile index c289c8d2..b44d5ac8 100644 --- a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile +++ b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile @@ -1,16 +1,19 @@ -FROM golang:1.23-alpine as builder +FROM golang:1.23-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH WORKDIR /workspace COPY go.mod go.sum ./ -RUN go mod download +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download COPY api api/ COPY pkg pkg/ COPY cmd cmd/ COPY internal internal/ -RUN CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /cozystack-controller cmd/cozystack-controller/main.go +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /cozystack-controller cmd/cozystack-controller/main.go FROM scratch diff --git a/packages/system/cozystack-controller/templates/rbac.yaml b/packages/system/cozystack-controller/templates/rbac.yaml index af3dae33..64f1eaa1 100644 --- a/packages/system/cozystack-controller/templates/rbac.yaml +++ b/packages/system/cozystack-controller/templates/rbac.yaml @@ -9,3 +9,6 @@ rules: - apiGroups: ['cozystack.io'] resources: ['*'] verbs: ['*'] +- apiGroups: ["helm.toolkit.fluxcd.io"] + resources: ["helmreleases"] + verbs: ["get", "list", "watch", "patch", "update"] diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index fdfe2481..fc77f625 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,5 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.30.2@sha256:5b87a8ea0dcde1671f44532c1ee6db11a5dd922d1a009078ecf6495ec193e52a + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.31.0-rc.3@sha256:b2f0de3ae2d7f15956eb7cdec78d2267aeba7e56a7781c70473757df4989a05a debug: false disableTelemetry: false - cozystackVersion: "v0.30.2" + cozystackVersion: "v0.31.0-rc.3" diff --git a/packages/system/dashboard/Makefile b/packages/system/dashboard/Makefile index c0267da1..10df5382 100644 --- a/packages/system/dashboard/Makefile +++ b/packages/system/dashboard/Makefile @@ -17,7 +17,8 @@ update-chart: patch --no-backup-if-mismatch charts/kubeapps/templates/frontend/configmap.yaml < patches/logos.patch update-dockerfiles: - tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/vmware-tanzu/kubeapps | awk -F'[/^]' 'END{print $$3}') && \ + @echo Update dockerfiles manually + #tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/vmware-tanzu/kubeapps | awk -F'[/^]' 'END{print $$3}') && \ wget https://github.com/vmware-tanzu/kubeapps/raw/$${tag}/cmd/kubeapps-apis/Dockerfile -O images/kubeapps-apis/Dockerfile && \ patch --no-backup-if-mismatch images/kubeapps-apis/Dockerfile < images/kubeapps-apis/dockerfile.diff && \ node_image=$$(wget -O- https://github.com/vmware-tanzu/kubeapps/raw/main/dashboard/Dockerfile | awk '/FROM bitnami\/node/ {print $$2}') && \ @@ -28,6 +29,8 @@ update-dockerfiles: image-dashboard: update-version docker buildx build images/dashboard \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/dashboard:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/dashboard:latest \ --cache-to type=inline \ @@ -48,6 +51,8 @@ image-dashboard: update-version image-kubeapps-apis: update-version docker buildx build images/kubeapps-apis \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/kubeapps-apis:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/kubeapps-apis:latest \ --cache-to type=inline \ diff --git a/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml b/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml index b1409d89..3d364d20 100644 --- a/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml +++ b/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml @@ -76,7 +76,7 @@ data: "kubeappsNamespace": {{ .Release.Namespace | quote }}, "helmGlobalNamespace": {{ include "kubeapps.helmGlobalPackagingNamespace" . | quote }}, "carvelGlobalNamespace": {{ .Values.kubeappsapis.pluginConfig.kappController.packages.v1alpha1.globalPackagingNamespace | quote }}, - "appVersion": "v0.30.2", + "appVersion": "v0.31.0-rc.3", "authProxyEnabled": {{ .Values.authProxy.enabled }}, "oauthLoginURI": {{ .Values.authProxy.oauthLoginURI | quote }}, "oauthLogoutURI": {{ .Values.authProxy.oauthLogoutURI | quote }}, diff --git a/packages/system/dashboard/images/kubeapps-apis/Dockerfile b/packages/system/dashboard/images/kubeapps-apis/Dockerfile index 05add84b..4825fb41 100644 --- a/packages/system/dashboard/images/kubeapps-apis/Dockerfile +++ b/packages/system/dashboard/images/kubeapps-apis/Dockerfile @@ -3,7 +3,7 @@ # syntax = docker/dockerfile:1 -FROM alpine as source +FROM alpine AS source ARG COMMIT_REF=dd02680d796c962b8dcc4e5ea70960a846c1acdc RUN apk add --no-cache patch WORKDIR /source @@ -12,8 +12,9 @@ RUN wget -O- https://github.com/cozystack/kubeapps/archive/${COMMIT_REF}.tar.gz FROM bitnami/golang:1.23.4 AS builder WORKDIR /go/src/github.com/vmware-tanzu/kubeapps COPY --from=source /source/go.mod /source/go.sum ./ -ARG VERSION="devel" +ARG TARGETOS ARG TARGETARCH +ARG VERSION="devel" # If true, run golangci-lint to detect issues ARG lint @@ -29,10 +30,12 @@ ARG GRPC_HEALTH_PROBE_VERSION="0.4.34" # Install lint tools RUN if [ ! -z ${lint:-} ]; then \ - go install github.com/golangci/golangci-lint/cmd/golangci-lint@v$GOLANGCILINT_VERSION; \ + GOOS=$TARGETOS GOARCH=$TARGETARCH go install github.com/golangci/golangci-lint/cmd/golangci-lint@v$GOLANGCILINT_VERSION; \ fi -RUN curl -sSL "https://github.com/bufbuild/buf/releases/download/v$BUF_VERSION/buf-Linux-x86_64" -o "/tmp/buf" && chmod +x "/tmp/buf" +RUN if [ $TARGETARCH = 'amd64' ]; then BUF_ARCH='x86_64'; elif [ $TARGETARCH = 'arm64' ]; then BUF_ARCH='aarch64'; fi && \ + if [ $TARGETOS = 'linux' ]; then BUF_PLATFORM='Linux'; fi && \ + curl -sSL "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-${BUF_PLATFORM}-${BUF_ARCH}" -o "/tmp/buf" && chmod +x "/tmp/buf" # TODO: Remove and instead use built-in gRPC container probes once we're supporting >= 1.24 only. https://kubernetes.io/blog/2022/05/13/grpc-probes-now-in-beta/ RUN curl -sSL "https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-${TARGETARCH}" -o "/bin/grpc_health_probe" && chmod +x "/bin/grpc_health_probe" @@ -41,7 +44,7 @@ RUN curl -sSL "https://github.com/grpc-ecosystem/grpc-health-probe/releases/down # https://github.com/golang/go/issues/27719#issuecomment-514747274 RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ - GOPROXY="https://proxy.golang.org,direct" go mod download + GOOS=$TARGETOS GOARCH=$TARGETARCH GOPROXY="https://proxy.golang.org,direct" go mod download # We don't copy the pkg and cmd directories until here so the above layers can # be reused. @@ -60,7 +63,7 @@ RUN /tmp/buf lint ./cmd/kubeapps-apis # Build the main grpc server RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ - GOPROXY="https://proxy.golang.org,direct" \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GOPROXY="https://proxy.golang.org,direct" \ go build \ -ldflags "-X github.com/vmware-tanzu/kubeapps/cmd/kubeapps-apis/cmd.version=$VERSION" \ ./cmd/kubeapps-apis @@ -68,7 +71,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \ ## Build 'fluxv2' plugin, version 'v1alpha1' RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ - GOPROXY="https://proxy.golang.org,direct" \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GOPROXY="https://proxy.golang.org,direct" \ go build \ -ldflags "-X github.com/vmware-tanzu/kubeapps/cmd/kubeapps-apis/cmd.version=$VERSION" \ -o /fluxv2-packages-v1alpha1-plugin.so -buildmode=plugin \ @@ -77,7 +80,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \ ## Build 'helm' plugin, version 'v1alpha1' RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ - GOPROXY="https://proxy.golang.org,direct" \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GOPROXY="https://proxy.golang.org,direct" \ go build \ -ldflags "-X github.com/vmware-tanzu/kubeapps/cmd/kubeapps-apis/cmd.version=$VERSION" \ -o /helm-packages-v1alpha1-plugin.so -buildmode=plugin \ @@ -86,7 +89,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \ ## Build 'resources' plugin, version 'v1alpha1' RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ - GOPROXY="https://proxy.golang.org,direct" \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GOPROXY="https://proxy.golang.org,direct" \ go build \ -ldflags "-X github.com/vmware-tanzu/kubeapps/cmd/kubeapps-apis/cmd.version=$VERSION" \ -o /resources-v1alpha1-plugin.so -buildmode=plugin \ diff --git a/packages/extra/ingress/templates/dashboard.yaml b/packages/system/dashboard/templates/dashboard-ingress.yaml similarity index 66% rename from packages/extra/ingress/templates/dashboard.yaml rename to packages/system/dashboard/templates/dashboard-ingress.yaml index 830e7a0a..1fd7f85d 100644 --- a/packages/extra/ingress/templates/dashboard.yaml +++ b/packages/system/dashboard/templates/dashboard-ingress.yaml @@ -1,10 +1,10 @@ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} {{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} +{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} - -{{- if .Values.dashboard }} +{{- if and (has "dashboard" $exposeServices) }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: @@ -12,16 +12,16 @@ metadata: cert-manager.io/cluster-issuer: letsencrypt-prod {{- if eq $issuerType "cloudflare" }} {{- else }} - acme.cert-manager.io/http01-ingress-class: {{ .Release.Namespace }} + acme.cert-manager.io/http01-ingress-class: {{ $exposeIngress }} + {{- end }} nginx.ingress.kubernetes.io/proxy-body-size: 100m nginx.ingress.kubernetes.io/proxy-buffer-size: 100m nginx.ingress.kubernetes.io/proxy-buffers-number: "4" nginx.ingress.kubernetes.io/client-max-body-size: 100m - {{- end }} - name: dashboard-{{ .Release.Namespace }} + name: dashboard namespace: cozy-dashboard spec: - ingressClassName: {{ .Release.Namespace }} + ingressClassName: {{ $exposeIngress }} rules: - host: dashboard.{{ $host }} http: @@ -36,5 +36,5 @@ spec: tls: - hosts: - dashboard.{{ $host }} - secretName: dashboard-{{ .Release.Namespace }}-tls + secretName: dashboard-tls {{- end }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index a6b91769..5d1a7ef4 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -19,15 +19,24 @@ kubeapps: image: registry: ghcr.io/cozystack/cozystack repository: dashboard - tag: v0.30.2 + tag: v0.31.0-rc.3 digest: "sha256:a83fe4654f547469cfa469a02bda1273c54bca103a41eb007fdb2e18a7a91e93" + redis: + master: + resourcesPreset: "none" + resources: + requests: + cpu: 200m + memory: 256Mi + limits: + memory: 256Mi kubeappsapis: resourcesPreset: "none" image: registry: ghcr.io/cozystack/cozystack repository: kubeapps-apis - tag: v0.30.2 - digest: "sha256:3b5805b56f2fb9fd25f4aa389cdfbbb28a3f2efb02245c52085a45d1dc62bf92" + tag: v0.31.0-rc.3 + digest: "sha256:1447c10fcc9a8de426ec381bce565aa56267d0c9f3bab8fe26ac502d433283c5" pluginConfig: flux: packages: diff --git a/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml b/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml index 93402076..43caa7d9 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml @@ -8,7 +8,7 @@ annotations: - name: Upstream Project url: https://github.com/controlplaneio-fluxcd/flux-operator apiVersion: v2 -appVersion: v0.18.0 +appVersion: v0.20.0 description: 'A Helm chart for deploying the Flux Operator. ' home: https://github.com/controlplaneio-fluxcd icon: https://raw.githubusercontent.com/cncf/artwork/main/projects/flux/icon/color/flux-icon-color.png @@ -25,4 +25,4 @@ sources: - https://github.com/controlplaneio-fluxcd/flux-operator - https://github.com/controlplaneio-fluxcd/charts type: application -version: 0.18.0 +version: 0.20.0 diff --git a/packages/system/fluxcd-operator/charts/flux-operator/README.md b/packages/system/fluxcd-operator/charts/flux-operator/README.md index 7a1090ac..7cbbd492 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/README.md +++ b/packages/system/fluxcd-operator/charts/flux-operator/README.md @@ -1,6 +1,6 @@ # flux-operator -![Version: 0.18.0](https://img.shields.io/badge/Version-0.18.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.18.0](https://img.shields.io/badge/AppVersion-v0.18.0-informational?style=flat-square) +![Version: 0.20.0](https://img.shields.io/badge/Version-0.20.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.20.0](https://img.shields.io/badge/AppVersion-v0.20.0-informational?style=flat-square) The [Flux Operator](https://github.com/controlplaneio-fluxcd/flux-operator) provides a declarative API for the installation and upgrade of CNCF [Flux](https://fluxcd.io) and the @@ -33,6 +33,7 @@ see the Flux Operator [documentation](https://fluxcd.control-plane.io/operator/) | Key | Type | Default | Description | |-----|------|---------|-------------| | affinity | object | `{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"kubernetes.io/os","operator":"In","values":["linux"]}]}]}}}` | Pod affinity and anti-affinity settings. | +| apiPriority | object | `{"enabled":false,"extraServiceAccounts":[],"level":"workload-high"}` | Kubernetes [API priority and fairness](https://kubernetes.io/docs/concepts/cluster-administration/flow-control/) settings. | | commonAnnotations | object | `{}` | Common annotations to add to all deployed objects including pods. | | commonLabels | object | `{}` | Common labels to add to all deployed objects including pods. | | extraArgs | list | `[]` | Container extra arguments. | diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml index ae7382df..abbf8990 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml @@ -18,6 +18,6 @@ roleRef: name: cluster-admin subjects: - kind: ServiceAccount - name: {{ include "flux-operator.fullname" . }} + name: {{ include "flux-operator.serviceAccountName" . }} namespace: {{ .Release.Namespace }} {{- end }} diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml index acdfed24..ff47d2c7 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml @@ -878,6 +878,18 @@ spec: required: - name type: object + skip: + description: Skip defines whether we need to skip input provider response + updates. + properties: + labels: + description: |- + Labels specifies list of labels to skip input provider response when any of the label conditions matched. + When prefixed with !, input provider response will be skipped if it does not have this label. + items: + type: string + type: array + type: object type: description: Type specifies the type of the input provider. enum: diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/flowschema.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/flowschema.yaml new file mode 100644 index 00000000..b01fab11 --- /dev/null +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/flowschema.yaml @@ -0,0 +1,41 @@ +{{- if .Values.apiPriority.enabled }} +apiVersion: flowcontrol.apiserver.k8s.io/v1 +kind: FlowSchema +metadata: + name: {{ include "flux-operator.fullname" . }} + annotations: + apf.kubernetes.io/autoupdate-spec: "false" +spec: + distinguisherMethod: + type: ByUser + matchingPrecedence: 950 + priorityLevelConfiguration: + name: {{ .Values.apiPriority.level }} + rules: + - nonResourceRules: + - nonResourceURLs: + - '*' + verbs: + - '*' + resourceRules: + - apiGroups: + - '*' + clusterScope: true + namespaces: + - '*' + resources: + - '*' + verbs: + - '*' + subjects: + - kind: ServiceAccount + serviceAccount: + name: {{ include "flux-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + {{- range .Values.apiPriority.extraServiceAccounts }} + - kind: ServiceAccount + serviceAccount: + name: {{ .name }} + namespace: {{ .namespace }} + {{- end }} +{{- end }} diff --git a/packages/system/fluxcd-operator/charts/flux-operator/values.schema.json b/packages/system/fluxcd-operator/charts/flux-operator/values.schema.json index b033d9f6..dc277e55 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/values.schema.json +++ b/packages/system/fluxcd-operator/charts/flux-operator/values.schema.json @@ -63,6 +63,25 @@ }, "type": "object" }, + "apiPriority": { + "default": { + "enabled": false, + "extraServiceAccounts": [], + "level": "workload-high" + }, + "properties": { + "enabled": { + "type": "boolean" + }, + "extraServiceAccounts": { + "type": "array" + }, + "level": { + "type": "string" + } + }, + "type": "object" + }, "commonAnnotations": { "properties": {}, "type": "object" diff --git a/packages/system/fluxcd-operator/charts/flux-operator/values.yaml b/packages/system/fluxcd-operator/charts/flux-operator/values.yaml index f1accd65..91cad9d2 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/values.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/values.yaml @@ -33,6 +33,16 @@ image: # Recommended value is system-cluster-critical. priorityClassName: "" # @schema default: "system-cluster-critical" +# -- Kubernetes [API priority and fairness](https://kubernetes.io/docs/concepts/cluster-administration/flow-control/) settings. +apiPriority: # @schema default: {"enabled":false,"level":"workload-high","extraServiceAccounts":[]} + enabled: false + level: workload-high + extraServiceAccounts: [] +# - name: kustomize-controller +# namespace: flux-system +# - name: helm-controller +# namespace: flux-system + # -- Container resources requests and limits settings. resources: # @schema required: true limits: diff --git a/packages/system/fluxcd/charts/flux-instance/Chart.yaml b/packages/system/fluxcd/charts/flux-instance/Chart.yaml index a065c181..12d1d3b4 100644 --- a/packages/system/fluxcd/charts/flux-instance/Chart.yaml +++ b/packages/system/fluxcd/charts/flux-instance/Chart.yaml @@ -8,7 +8,7 @@ annotations: - name: Upstream Project url: https://github.com/controlplaneio-fluxcd/flux-operator apiVersion: v2 -appVersion: v0.18.0 +appVersion: v0.20.0 description: 'A Helm chart for deploying a Flux instance managed by Flux Operator. ' home: https://github.com/controlplaneio-fluxcd icon: https://raw.githubusercontent.com/cncf/artwork/main/projects/flux/icon/color/flux-icon-color.png @@ -25,4 +25,4 @@ sources: - https://github.com/controlplaneio-fluxcd/flux-operator - https://github.com/controlplaneio-fluxcd/charts type: application -version: 0.18.0 +version: 0.20.0 diff --git a/packages/system/fluxcd/charts/flux-instance/README.md b/packages/system/fluxcd/charts/flux-instance/README.md index d56bb5f2..b39c70fc 100644 --- a/packages/system/fluxcd/charts/flux-instance/README.md +++ b/packages/system/fluxcd/charts/flux-instance/README.md @@ -1,6 +1,6 @@ # flux-instance -![Version: 0.18.0](https://img.shields.io/badge/Version-0.18.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.18.0](https://img.shields.io/badge/AppVersion-v0.18.0-informational?style=flat-square) +![Version: 0.20.0](https://img.shields.io/badge/Version-0.20.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.20.0](https://img.shields.io/badge/AppVersion-v0.20.0-informational?style=flat-square) This chart is a thin wrapper around the `FluxInstance` custom resource, which is used by the [Flux Operator](https://github.com/controlplaneio-fluxcd/flux-operator) diff --git a/packages/system/fluxcd/values.yaml b/packages/system/fluxcd/values.yaml index 6318ebee..9eea6c6a 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -4,6 +4,7 @@ flux-instance: networkPolicy: true domain: cozy.local # -- default value is overriden in patches distribution: + artifact: "" version: 2.5.x registry: ghcr.io/fluxcd components: diff --git a/packages/system/gateway-api-crds/Chart.yaml b/packages/system/gateway-api-crds/Chart.yaml new file mode 100644 index 00000000..a6c8d105 --- /dev/null +++ b/packages/system/gateway-api-crds/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-gateway-api-crds +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/gateway-api-crds/Makefile b/packages/system/gateway-api-crds/Makefile new file mode 100644 index 00000000..c4311662 --- /dev/null +++ b/packages/system/gateway-api-crds/Makefile @@ -0,0 +1,9 @@ +export NAME=gateway-api-crds +export NAMESPACE=cozy-$(NAME) + +include ../../../scripts/package.mk + +update: + rm -rf templates + mkdir templates + kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v1.2.0" > templates/crds-experimental.yaml diff --git a/packages/system/gateway-api-crds/templates/crds-experimental.yaml b/packages/system/gateway-api-crds/templates/crds-experimental.yaml new file mode 100644 index 00000000..88b3060e --- /dev/null +++ b/packages/system/gateway-api-crds/templates/crds-experimental.yaml @@ -0,0 +1,14926 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + labels: + gateway.networking.k8s.io/policy: Direct + name: backendlbpolicies.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: BackendLBPolicy + listKind: BackendLBPolicyList + plural: backendlbpolicies + shortNames: + - blbpolicy + singular: backendlbpolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + BackendLBPolicy provides a way to define load balancing rules + for a backend. + 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: + description: Spec defines the desired state of BackendLBPolicy. + properties: + sessionPersistence: + description: |- + SessionPersistence defines and configures session persistence + for the backend. + + Support: Extended + properties: + absoluteTimeout: + description: |- + AbsoluteTimeout defines the absolute timeout of the persistent + session. Once the AbsoluteTimeout duration has elapsed, the + session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + cookieConfig: + description: |- + CookieConfig provides configuration settings that are specific + to cookie-based session persistence. + + Support: Core + properties: + lifetimeType: + default: Session + description: |- + LifetimeType specifies whether the cookie has a permanent or + session-based lifetime. A permanent cookie persists until its + specified expiry time, defined by the Expires or Max-Age cookie + attributes, while a session cookie is deleted when the current + session ends. + + When set to "Permanent", AbsoluteTimeout indicates the + cookie's lifetime via the Expires or Max-Age cookie attributes + and is required. + + When set to "Session", AbsoluteTimeout indicates the + absolute lifetime of the cookie tracked by the gateway and + is optional. + + Support: Core for "Session" type + + Support: Extended for "Permanent" type + enum: + - Permanent + - Session + type: string + type: object + idleTimeout: + description: |- + IdleTimeout defines the idle timeout of the persistent session. + Once the session has been idle for more than the specified + IdleTimeout duration, the session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + sessionName: + description: |- + SessionName defines the name of the persistent session token + which may be reflected in the cookie or the header. Users + should avoid reusing session names to prevent unintended + consequences, such as rejection or unpredictable behavior. + + Support: Implementation-specific + maxLength: 128 + type: string + type: + default: Cookie + description: |- + Type defines the type of session persistence such as through + the use a header or cookie. Defaults to cookie based session + persistence. + + Support: Core for "Cookie" type + + Support: Extended for "Header" type + enum: + - Cookie + - Header + type: string + type: object + x-kubernetes-validations: + - message: AbsoluteTimeout must be specified when cookie lifetimeType + is Permanent + rule: '!has(self.cookieConfig) || !has(self.cookieConfig.lifetimeType) + || self.cookieConfig.lifetimeType != ''Permanent'' || has(self.absoluteTimeout)' + targetRefs: + description: |- + TargetRef identifies an API object to apply policy to. + Currently, Backends (i.e. Service, ServiceImport, or any + implementation-specific backendRef) are the only valid API + target references. + items: + description: |- + LocalPolicyTargetReference identifies an API object to apply a direct or + inherited policy to. This should be used as part of Policy resources + that can target Gateway API resources. For more information on how this + policy attachment model works, and a sample Policy resource, refer to + the policy attachment documentation for Gateway API. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - group + - kind + - name + x-kubernetes-list-type: map + required: + - targetRefs + type: object + status: + description: Status defines the current state of BackendLBPolicy. + properties: + ancestors: + description: |- + Ancestors is a list of ancestor resources (usually Gateways) that are + associated with the policy, and the status of the policy with respect to + each ancestor. When this policy attaches to a parent, the controller that + manages the parent and the ancestors MUST add an entry to this list when + the controller first sees the policy and SHOULD update the entry as + appropriate when the relevant ancestor is modified. + + Note that choosing the relevant ancestor is left to the Policy designers; + an important part of Policy design is designing the right object level at + which to namespace this status. + + Note also that implementations MUST ONLY populate ancestor status for + the Ancestor resources they are responsible for. Implementations MUST + use the ControllerName field to uniquely identify the entries in this list + that they are responsible for. + + Note that to achieve this, the list of PolicyAncestorStatus structs + MUST be treated as a map with a composite key, made up of the AncestorRef + and ControllerName fields combined. + + A maximum of 16 ancestors will be represented in this list. An empty list + means the Policy is not relevant for any ancestors. + + If this slice is full, implementations MUST NOT add further entries. + Instead they MUST consider the policy unimplementable and signal that + on any related resources such as the ancestor that would be referenced + here. For example, if this list was full on BackendTLSPolicy, no + additional Gateways would be able to reference the Service targeted by + the BackendTLSPolicy. + items: + description: |- + PolicyAncestorStatus describes the status of a route with respect to an + associated Ancestor. + + Ancestors refer to objects that are either the Target of a policy or above it + in terms of object hierarchy. For example, if a policy targets a Service, the + Policy's Ancestors are, in order, the Service, the HTTPRoute, the Gateway, and + the GatewayClass. Almost always, in this hierarchy, the Gateway will be the most + useful object to place Policy status on, so we recommend that implementations + SHOULD use Gateway as the PolicyAncestorStatus object unless the designers + have a _very_ good reason otherwise. + + In the context of policy attachment, the Ancestor is used to distinguish which + resource results in a distinct application of this policy. For example, if a policy + targets a Service, it may have a distinct result per attached Gateway. + + Policies targeting the same resource may have different effects depending on the + ancestors of those resources. For example, different Gateways targeting the same + Service may have different capabilities, especially if they have different underlying + implementations. + + For example, in BackendTLSPolicy, the Policy attaches to a Service that is + used as a backend in a HTTPRoute that is itself attached to a Gateway. + In this case, the relevant object for status is the Gateway, and that is the + ancestor object referred to in this status. + + Note that a parent is also an ancestor, so for objects where the parent is the + relevant object for status, this struct SHOULD still be used. + + This struct is intended to be used in a slice that's effectively a map, + with a composite key made up of the AncestorRef and the ControllerName. + properties: + ancestorRef: + description: |- + AncestorRef corresponds with a ParentRef in the spec that this + PolicyAncestorStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + conditions: + description: Conditions describes the status of the Policy with + respect to the given Ancestor. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + required: + - ancestorRef + - controllerName + type: object + maxItems: 16 + type: array + required: + - ancestors + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + labels: + gateway.networking.k8s.io/policy: Direct + name: backendtlspolicies.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: BackendTLSPolicy + listKind: BackendTLSPolicyList + plural: backendtlspolicies + shortNames: + - btlspolicy + singular: backendtlspolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + BackendTLSPolicy provides a way to configure how a Gateway + connects to a Backend via TLS. + 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: + description: Spec defines the desired state of BackendTLSPolicy. + properties: + options: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Options are a list of key/value pairs to enable extended TLS + configuration for each implementation. For example, configuring the + minimum TLS version or supported cipher suites. + + A set of common keys MAY be defined by the API in the future. To avoid + any ambiguity, implementation-specific definitions MUST use + domain-prefixed names, such as `example.com/my-custom-option`. + Un-prefixed names are reserved for key names defined by Gateway API. + + Support: Implementation-specific + maxProperties: 16 + type: object + targetRefs: + description: |- + TargetRefs identifies an API object to apply the policy to. + Only Services have Extended support. Implementations MAY support + additional objects, with Implementation Specific support. + Note that this config applies to the entire referenced resource + by default, but this default may change in the future to provide + a more granular application of the policy. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + items: + description: |- + LocalPolicyTargetReferenceWithSectionName identifies an API object to apply a + direct policy to. This should be used as part of Policy resources that can + target single resources. For more information on how this policy attachment + mode works, and a sample Policy resource, refer to the policy attachment + documentation for Gateway API. + + Note: This should only be used for direct policy attachment when references + to SectionName are actually needed. In all other cases, + LocalPolicyTargetReference should be used. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + sectionName: + description: |- + SectionName is the name of a section within the target resource. When + unspecified, this targetRef targets the entire resource. In the following + resources, SectionName is interpreted as the following: + + * Gateway: Listener name + * HTTPRoute: HTTPRouteRule name + * Service: Port name + + If a SectionName is specified, but does not exist on the targeted object, + the Policy must fail to attach, and the policy implementation should record + a `ResolvedRefs` or similar Condition in the Policy's status. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 16 + minItems: 1 + type: array + validation: + description: Validation contains backend TLS validation configuration. + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to Kubernetes objects that + contain a PEM-encoded TLS CA certificate bundle, which is used to + validate a TLS handshake between the Gateway and backend Pod. + + If CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be + specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified, + not both. If CACertifcateRefs is empty or unspecified, the configuration for + WellKnownCACertificates MUST be honored instead if supported by the implementation. + + References to a resource in a different namespace are invalid for the + moment, although we will revisit this in the future. + + A single CACertificateRef to a Kubernetes ConfigMap kind has "Core" support. + Implementations MAY choose to support attaching multiple certificates to + a backend, but this behavior is implementation-specific. + + Support: Core - An optional single reference to a Kubernetes ConfigMap, + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one reference, or other kinds + of resources). + items: + description: |- + LocalObjectReference identifies an API object within the namespace of the + referrer. + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example "HTTPRoute" + or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + type: array + hostname: + description: |- + Hostname is used for two purposes in the connection between Gateways and + backends: + + 1. Hostname MUST be used as the SNI to connect to the backend (RFC 6066). + 2. If SubjectAltNames is not specified, Hostname MUST be used for + authentication and MUST match the certificate served by the matching + backend. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + subjectAltNames: + description: |- + SubjectAltNames contains one or more Subject Alternative Names. + When specified, the certificate served from the backend MUST have at least one + Subject Alternate Name matching one of the specified SubjectAltNames. + + Support: Core + items: + description: SubjectAltName represents Subject Alternative Name. + properties: + hostname: + description: |- + Hostname contains Subject Alternative Name specified in DNS name format. + Required when Type is set to Hostname, ignored otherwise. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: + description: |- + Type determines the format of the Subject Alternative Name. Always required. + + Support: Core + enum: + - Hostname + - URI + type: string + uri: + description: |- + URI contains Subject Alternative Name specified in a full URI format. + It MUST include both a scheme (e.g., "http" or "ftp") and a scheme-specific-part. + Common values include SPIFFE IDs like "spiffe://mycluster.example.com/ns/myns/sa/svc1sa". + Required when Type is set to URI, ignored otherwise. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^(([^:/?#]+):)(//([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))? + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: SubjectAltName element must contain Hostname, if + Type is set to Hostname + rule: '!(self.type == "Hostname" && (!has(self.hostname) || + self.hostname == ""))' + - message: SubjectAltName element must not contain Hostname, + if Type is not set to Hostname + rule: '!(self.type != "Hostname" && has(self.hostname) && + self.hostname != "")' + - message: SubjectAltName element must contain URI, if Type + is set to URI + rule: '!(self.type == "URI" && (!has(self.uri) || self.uri + == ""))' + - message: SubjectAltName element must not contain URI, if Type + is not set to URI + rule: '!(self.type != "URI" && has(self.uri) && self.uri != + "")' + maxItems: 5 + type: array + wellKnownCACertificates: + description: |- + WellKnownCACertificates specifies whether system CA certificates may be used in + the TLS handshake between the gateway and backend pod. + + If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs + must be specified with at least one entry for a valid configuration. Only one of + CACertificateRefs or WellKnownCACertificates may be specified, not both. If an + implementation does not support the WellKnownCACertificates field or the value + supplied is not supported, the Status Conditions on the Policy MUST be + updated to include an Accepted: False Condition with Reason: Invalid. + + Support: Implementation-specific + enum: + - System + type: string + required: + - hostname + type: object + x-kubernetes-validations: + - message: must not contain both CACertificateRefs and WellKnownCACertificates + rule: '!(has(self.caCertificateRefs) && size(self.caCertificateRefs) + > 0 && has(self.wellKnownCACertificates) && self.wellKnownCACertificates + != "")' + - message: must specify either CACertificateRefs or WellKnownCACertificates + rule: (has(self.caCertificateRefs) && size(self.caCertificateRefs) + > 0 || has(self.wellKnownCACertificates) && self.wellKnownCACertificates + != "") + required: + - targetRefs + - validation + type: object + status: + description: Status defines the current state of BackendTLSPolicy. + properties: + ancestors: + description: |- + Ancestors is a list of ancestor resources (usually Gateways) that are + associated with the policy, and the status of the policy with respect to + each ancestor. When this policy attaches to a parent, the controller that + manages the parent and the ancestors MUST add an entry to this list when + the controller first sees the policy and SHOULD update the entry as + appropriate when the relevant ancestor is modified. + + Note that choosing the relevant ancestor is left to the Policy designers; + an important part of Policy design is designing the right object level at + which to namespace this status. + + Note also that implementations MUST ONLY populate ancestor status for + the Ancestor resources they are responsible for. Implementations MUST + use the ControllerName field to uniquely identify the entries in this list + that they are responsible for. + + Note that to achieve this, the list of PolicyAncestorStatus structs + MUST be treated as a map with a composite key, made up of the AncestorRef + and ControllerName fields combined. + + A maximum of 16 ancestors will be represented in this list. An empty list + means the Policy is not relevant for any ancestors. + + If this slice is full, implementations MUST NOT add further entries. + Instead they MUST consider the policy unimplementable and signal that + on any related resources such as the ancestor that would be referenced + here. For example, if this list was full on BackendTLSPolicy, no + additional Gateways would be able to reference the Service targeted by + the BackendTLSPolicy. + items: + description: |- + PolicyAncestorStatus describes the status of a route with respect to an + associated Ancestor. + + Ancestors refer to objects that are either the Target of a policy or above it + in terms of object hierarchy. For example, if a policy targets a Service, the + Policy's Ancestors are, in order, the Service, the HTTPRoute, the Gateway, and + the GatewayClass. Almost always, in this hierarchy, the Gateway will be the most + useful object to place Policy status on, so we recommend that implementations + SHOULD use Gateway as the PolicyAncestorStatus object unless the designers + have a _very_ good reason otherwise. + + In the context of policy attachment, the Ancestor is used to distinguish which + resource results in a distinct application of this policy. For example, if a policy + targets a Service, it may have a distinct result per attached Gateway. + + Policies targeting the same resource may have different effects depending on the + ancestors of those resources. For example, different Gateways targeting the same + Service may have different capabilities, especially if they have different underlying + implementations. + + For example, in BackendTLSPolicy, the Policy attaches to a Service that is + used as a backend in a HTTPRoute that is itself attached to a Gateway. + In this case, the relevant object for status is the Gateway, and that is the + ancestor object referred to in this status. + + Note that a parent is also an ancestor, so for objects where the parent is the + relevant object for status, this struct SHOULD still be used. + + This struct is intended to be used in a slice that's effectively a map, + with a composite key made up of the AncestorRef and the ControllerName. + properties: + ancestorRef: + description: |- + AncestorRef corresponds with a ParentRef in the spec that this + PolicyAncestorStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + conditions: + description: Conditions describes the status of the Policy with + respect to the given Ancestor. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + required: + - ancestorRef + - controllerName + type: object + maxItems: 16 + type: array + required: + - ancestors + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: gatewayclasses.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: GatewayClass + listKind: GatewayClassList + plural: gatewayclasses + shortNames: + - gc + singular: gatewayclass + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.controllerName + name: Controller + type: string + - jsonPath: .status.conditions[?(@.type=="Accepted")].status + name: Accepted + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.description + name: Description + priority: 1 + type: string + name: v1 + schema: + openAPIV3Schema: + description: |- + GatewayClass describes a class of Gateways available to the user for creating + Gateway resources. + + It is recommended that this resource be used as a template for Gateways. This + means that a Gateway is based on the state of the GatewayClass at the time it + was created and changes to the GatewayClass or associated parameters are not + propagated down to existing Gateways. This recommendation is intended to + limit the blast radius of changes to GatewayClass or associated parameters. + If implementations choose to propagate GatewayClass changes to existing + Gateways, that MUST be clearly documented by the implementation. + + Whenever one or more Gateways are using a GatewayClass, implementations SHOULD + add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the + associated GatewayClass. This ensures that a GatewayClass associated with a + Gateway is not deleted while in use. + + GatewayClass is a Cluster level resource. + 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: + description: Spec defines the desired state of GatewayClass. + properties: + controllerName: + description: |- + ControllerName is the name of the controller that is managing Gateways of + this class. The value of this field MUST be a domain prefixed path. + + Example: "example.net/gateway-controller". + + This field is not mutable and cannot be empty. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + description: + description: Description helps describe a GatewayClass with more details. + maxLength: 64 + type: string + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the GatewayClass. This is optional if the + controller does not require any additional configuration. + + ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, + or an implementation-specific custom resource. The resource can be + cluster-scoped or namespace-scoped. + + If the referent cannot be found, refers to an unsupported kind, or when + the data within that resource is malformed, the GatewayClass SHOULD be + rejected with the "Accepted" status condition set to "False" and an + "InvalidParameters" reason. + + A Gateway for this GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. + This field is required when referring to a Namespace-scoped resource and + MUST be unset when referring to a Cluster-scoped resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + required: + - controllerName + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Status defines the current state of GatewayClass. + + Implementations MUST populate status on all GatewayClass resources which + specify their controller name. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Conditions is the current status from the controller for + this GatewayClass. + + Controllers should prefer to publish conditions using values + of GatewayClassConditionType for the type of each Condition. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + supportedFeatures: + description: | + SupportedFeatures is the set of features the GatewayClass support. + It MUST be sorted in ascending alphabetical order by the Name key. + items: + properties: + name: + description: |- + FeatureName is used to describe distinct features that are covered by + conformance tests. + type: string + required: + - name + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.controllerName + name: Controller + type: string + - jsonPath: .status.conditions[?(@.type=="Accepted")].status + name: Accepted + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.description + name: Description + priority: 1 + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + GatewayClass describes a class of Gateways available to the user for creating + Gateway resources. + + It is recommended that this resource be used as a template for Gateways. This + means that a Gateway is based on the state of the GatewayClass at the time it + was created and changes to the GatewayClass or associated parameters are not + propagated down to existing Gateways. This recommendation is intended to + limit the blast radius of changes to GatewayClass or associated parameters. + If implementations choose to propagate GatewayClass changes to existing + Gateways, that MUST be clearly documented by the implementation. + + Whenever one or more Gateways are using a GatewayClass, implementations SHOULD + add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the + associated GatewayClass. This ensures that a GatewayClass associated with a + Gateway is not deleted while in use. + + GatewayClass is a Cluster level resource. + 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: + description: Spec defines the desired state of GatewayClass. + properties: + controllerName: + description: |- + ControllerName is the name of the controller that is managing Gateways of + this class. The value of this field MUST be a domain prefixed path. + + Example: "example.net/gateway-controller". + + This field is not mutable and cannot be empty. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + description: + description: Description helps describe a GatewayClass with more details. + maxLength: 64 + type: string + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the GatewayClass. This is optional if the + controller does not require any additional configuration. + + ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, + or an implementation-specific custom resource. The resource can be + cluster-scoped or namespace-scoped. + + If the referent cannot be found, refers to an unsupported kind, or when + the data within that resource is malformed, the GatewayClass SHOULD be + rejected with the "Accepted" status condition set to "False" and an + "InvalidParameters" reason. + + A Gateway for this GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. + This field is required when referring to a Namespace-scoped resource and + MUST be unset when referring to a Cluster-scoped resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + required: + - controllerName + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Status defines the current state of GatewayClass. + + Implementations MUST populate status on all GatewayClass resources which + specify their controller name. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + description: |- + Conditions is the current status from the controller for + this GatewayClass. + + Controllers should prefer to publish conditions using values + of GatewayClassConditionType for the type of each Condition. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + supportedFeatures: + description: | + SupportedFeatures is the set of features the GatewayClass support. + It MUST be sorted in ascending alphabetical order by the Name key. + items: + properties: + name: + description: |- + FeatureName is used to describe distinct features that are covered by + conformance tests. + type: string + required: + - name + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: gateways.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gtw + singular: gateway + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.gatewayClassName + name: Class + type: string + - jsonPath: .status.addresses[*].value + name: Address + type: string + - jsonPath: .status.conditions[?(@.type=="Programmed")].status + name: Programmed + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + Gateway represents an instance of a service-traffic handling infrastructure + by binding Listeners to a set of IP addresses. + 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: + description: Spec defines the desired state of Gateway. + properties: + addresses: + description: |+ + Addresses requested for this Gateway. This is optional and behavior can + depend on the implementation. If a value is set in the spec and the + requested address is invalid or unavailable, the implementation MUST + indicate this in the associated entry in GatewayStatus.Addresses. + + The Addresses field represents a request for the address(es) on the + "outside of the Gateway", that traffic bound for this Gateway will use. + This could be the IP address or hostname of an external load balancer or + other networking infrastructure, or some other address that traffic will + be sent to. + + If no Addresses are specified, the implementation MAY schedule the + Gateway in an implementation-specific manner, assigning an appropriate + set of Addresses. + + The implementation MUST bind all Listeners to every GatewayAddress that + it assigns to the Gateway and add a corresponding entry in + GatewayStatus.Addresses. + + Support: Extended + + items: + description: GatewayAddress describes an address that can be bound + to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + backendTLS: + description: |+ + BackendTLS configures TLS settings for when this Gateway is connecting to + backends with TLS. + + Support: Core + + properties: + clientCertificateRef: + description: |+ + ClientCertificateRef is a reference to an object that contains a Client + Certificate and the associated private key. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + ClientCertificateRef can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + This setting can be overridden on the service level by use of BackendTLSPolicy. + + Support: Core + + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + gatewayClassName: + description: |- + GatewayClassName used for this Gateway. This is the name of a + GatewayClass resource. + maxLength: 253 + minLength: 1 + type: string + infrastructure: + description: |- + Infrastructure defines infrastructure level attributes about this Gateway instance. + + Support: Extended + properties: + annotations: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Annotations that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.annotations` field on resources. + For other implementations, this refers to any relevant (implementation specific) "annotations" concepts. + + An implementation may chose to add additional implementation-specific annotations as they see fit. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Annotation keys must be in the form of an optional + DNS subdomain prefix followed by a required name segment of + up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the annotation key's prefix must be a + DNS subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + labels: + additionalProperties: + description: |- + LabelValue is the value of a label in the Gateway API. This is used for validation + of maps such as Gateway infrastructure labels. This matches the Kubernetes + label validation rules: + * must be 63 characters or less (can be empty), + * unless empty, must begin and end with an alphanumeric character ([a-z0-9A-Z]), + * could contain dashes (-), underscores (_), dots (.), and alphanumerics between. + + Valid values include: + + * MyValue + * my.name + * 123-my-value + maxLength: 63 + minLength: 0 + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + description: |- + Labels that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.labels` field on resources. + For other implementations, this refers to any relevant (implementation specific) "labels" concepts. + + An implementation may chose to add additional implementation-specific labels as they see fit. + + If an implementation maps these labels to Pods, or any other resource that would need to be recreated when labels + change, it SHOULD clearly warn about this behavior in documentation. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Label keys must be in the form of an optional DNS subdomain + prefix followed by a required name segment of up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the label key's prefix must be a DNS + subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the Gateway. This is optional if the + controller does not require any additional configuration. + + This follows the same semantics as GatewayClass's `parametersRef`, but on a per-Gateway basis + + The Gateway's GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + type: object + listeners: + description: |- + Listeners associated with this Gateway. Listeners define + logical endpoints that are bound on this Gateway's addresses. + At least one Listener MUST be specified. + + Each Listener in a set of Listeners (for example, in a single Gateway) + MUST be _distinct_, in that a traffic flow MUST be able to be assigned to + exactly one listener. (This section uses "set of Listeners" rather than + "Listeners in a single Gateway" because implementations MAY merge configuration + from multiple Gateways onto a single data plane, and these rules _also_ + apply in that case). + + Practically, this means that each listener in a set MUST have a unique + combination of Port, Protocol, and, if supported by the protocol, Hostname. + + Some combinations of port, protocol, and TLS settings are considered + Core support and MUST be supported by implementations based on their + targeted conformance profile: + + HTTP Profile + + 1. HTTPRoute, Port: 80, Protocol: HTTP + 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: Terminate, TLS keypair provided + + TLS Profile + + 1. TLSRoute, Port: 443, Protocol: TLS, TLS Mode: Passthrough + + "Distinct" Listeners have the following property: + + The implementation can match inbound requests to a single distinct + Listener. When multiple Listeners share values for fields (for + example, two Listeners with the same Port value), the implementation + can match requests to only one of the Listeners using other + Listener fields. + + For example, the following Listener scenarios are distinct: + + 1. Multiple Listeners with the same Port that all use the "HTTP" + Protocol that all have unique Hostname values. + 2. Multiple Listeners with the same Port that use either the "HTTPS" or + "TLS" Protocol that all have unique Hostname values. + 3. A mixture of "TCP" and "UDP" Protocol Listeners, where no Listener + with the same Protocol has the same Port value. + + Some fields in the Listener struct have possible values that affect + whether the Listener is distinct. Hostname is particularly relevant + for HTTP or HTTPS protocols. + + When using the Hostname value to select between same-Port, same-Protocol + Listeners, the Hostname value must be different on each Listener for the + Listener to be distinct. + + When the Listeners are distinct based on Hostname, inbound request + hostnames MUST match from the most specific to least specific Hostname + values to choose the correct Listener and its associated set of Routes. + + Exact matches must be processed before wildcard matches, and wildcard + matches must be processed before fallback (empty Hostname value) + matches. For example, `"foo.example.com"` takes precedence over + `"*.example.com"`, and `"*.example.com"` takes precedence over `""`. + + Additionally, if there are multiple wildcard entries, more specific + wildcard entries must be processed before less specific wildcard entries. + For example, `"*.foo.example.com"` takes precedence over `"*.example.com"`. + The precise definition here is that the higher the number of dots in the + hostname to the right of the wildcard character, the higher the precedence. + + The wildcard character will match any number of characters _and dots_ to + the left, however, so `"*.example.com"` will match both + `"foo.bar.example.com"` _and_ `"bar.example.com"`. + + If a set of Listeners contains Listeners that are not distinct, then those + Listeners are Conflicted, and the implementation MUST set the "Conflicted" + condition in the Listener Status to "True". + + Implementations MAY choose to accept a Gateway with some Conflicted + Listeners only if they only accept the partial Listener set that contains + no Conflicted Listeners. To put this another way, implementations may + accept a partial Listener set only if they throw out *all* the conflicting + Listeners. No picking one of the conflicting listeners as the winner. + This also means that the Gateway must have at least one non-conflicting + Listener in this case, otherwise it violates the requirement that at + least one Listener must be present. + + The implementation MUST set a "ListenersNotValid" condition on the + Gateway Status when the Gateway contains Conflicted Listeners whether or + not they accept the Gateway. That Condition SHOULD clearly + indicate in the Message which Listeners are conflicted, and which are + Accepted. Additionally, the Listener status for those listeners SHOULD + indicate which Listeners are conflicted and not Accepted. + + A Gateway's Listeners are considered "compatible" if: + + 1. They are distinct. + 2. The implementation can serve them in compliance with the Addresses + requirement that all Listeners are available on all assigned + addresses. + + Compatible combinations in Extended support are expected to vary across + implementations. A combination that is compatible for one implementation + may not be compatible for another. + + For example, an implementation that cannot serve both TCP and UDP listeners + on the same address, or cannot mix HTTPS and generic TLS listens on the same port + would not consider those cases compatible, even though they are distinct. + + Note that requests SHOULD match at most one Listener. For example, if + Listeners are defined for "foo.example.com" and "*.example.com", a + request to "foo.example.com" SHOULD only be routed using routes attached + to the "foo.example.com" Listener (and not the "*.example.com" Listener). + This concept is known as "Listener Isolation". Implementations that do + not support Listener Isolation MUST clearly document this. + + Implementations MAY merge separate Gateways onto a single set of + Addresses if all Listeners across all Gateways are compatible. + + Support: Core + items: + description: |- + Listener embodies the concept of a logical endpoint where a Gateway accepts + network connections. + properties: + allowedRoutes: + default: + namespaces: + from: Same + description: |- + AllowedRoutes defines the types of routes that MAY be attached to a + Listener and the trusted namespaces where those Route resources MAY be + present. + + Although a client request may match multiple route rules, only one rule + may ultimately receive the request. Matching precedence MUST be + determined in order of the following criteria: + + * The most specific match as defined by the Route type. + * The oldest Route based on creation timestamp. For example, a Route with + a creation timestamp of "2020-09-08 01:02:03" is given precedence over + a Route with a creation timestamp of "2020-09-08 01:02:04". + * If everything else is equivalent, the Route appearing first in + alphabetical order (namespace/name) should be given precedence. For + example, foo/bar is given precedence over foo/baz. + + All valid rules within a Route attached to this Listener should be + implemented. Invalid Route rules can be ignored (sometimes that will mean + the full Route). If a Route rule transitions from valid to invalid, + support for that Route rule should be dropped to ensure consistency. For + example, even if a filter specified by a Route rule is invalid, the rest + of the rules within that Route should still be supported. + + Support: Core + properties: + kinds: + description: |- + Kinds specifies the groups and kinds of Routes that are allowed to bind + to this Gateway Listener. When unspecified or empty, the kinds of Routes + selected are determined using the Listener protocol. + + A RouteGroupKind MUST correspond to kinds of Routes that are compatible + with the application protocol specified in the Listener's Protocol field. + If an implementation does not support or recognize this resource type, it + MUST set the "ResolvedRefs" condition to False for this Listener with the + "InvalidRouteKinds" reason. + + Support: Core + items: + description: RouteGroupKind indicates the group and kind + of a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + namespaces: + default: + from: Same + description: |- + Namespaces indicates namespaces from which Routes may be attached to this + Listener. This is restricted to the namespace of this Gateway by default. + + Support: Core + properties: + from: + default: Same + description: |- + From indicates where Routes will be selected for this Gateway. Possible + values are: + + * All: Routes in all namespaces may be used by this Gateway. + * Selector: Routes in namespaces selected by the selector may be used by + this Gateway. + * Same: Only Routes in the same namespace may be used by this Gateway. + + Support: Core + enum: + - All + - Selector + - Same + type: string + selector: + description: |- + Selector must be specified when From is set to "Selector". In that case, + only Routes in Namespaces matching this Selector will be selected by this + Gateway. This field is ignored for other values of "From". + + Support: Core + 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 + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + 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 + x-kubernetes-map-type: atomic + type: object + type: object + hostname: + description: |- + Hostname specifies the virtual hostname to match for protocol types that + define this concept. When unspecified, all hostnames are matched. This + field is ignored for protocols that don't require hostname based + matching. + + Implementations MUST apply Hostname matching appropriately for each of + the following protocols: + + * TLS: The Listener Hostname MUST match the SNI. + * HTTP: The Listener Hostname MUST match the Host header of the request. + * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP + protocol layers as described above. If an implementation does not + ensure that both the SNI and Host header match the Listener hostname, + it MUST clearly document that. + + For HTTPRoute and TLSRoute resources, there is an interaction with the + `spec.hostnames` array. When both listener and route specify hostnames, + there MUST be an intersection between the values for a Route to be + accepted. For more information, refer to the Route specific Hostnames + documentation. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + name: + description: |- + Name is the name of the Listener. This name MUST be unique within a + Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: |- + Port is the network port. Multiple listeners may use the + same port, subject to the Listener compatibility rules. + + Support: Core + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: |- + Protocol specifies the network protocol this listener expects to receive. + + Support: Core + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ + type: string + tls: + description: |- + TLS is the TLS configuration for the Listener. This field is required if + the Protocol field is "HTTPS" or "TLS". It is invalid to set this field + if the Protocol field is "HTTP", "TCP", or "UDP". + + The association of SNIs to Certificate defined in GatewayTLSConfig is + defined based on the Hostname field for this listener. + + The GatewayClass MUST use the longest matching SNI out of all + available certificates for any TLS handshake. + + Support: Core + properties: + certificateRefs: + description: |- + CertificateRefs contains a series of references to Kubernetes objects that + contains TLS certificates and private keys. These certificates are used to + establish a TLS handshake for requests that match the hostname of the + associated listener. + + A single CertificateRef to a Kubernetes Secret has "Core" support. + Implementations MAY choose to support attaching multiple certificates to + a Listener, but this behavior is implementation-specific. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + This field is required to have at least one element when the mode is set + to "Terminate" (default) and is optional otherwise. + + CertificateRefs can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls + + Support: Implementation-specific (More than one reference or other resource types) + items: + description: |- + SecretObjectReference identifies an API object including its namespace, + defaulting to Secret. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + maxItems: 64 + type: array + frontendValidation: + description: |+ + FrontendValidation holds configuration information for validating the frontend (client). + Setting this field will require clients to send a client certificate + required for validation during the TLS handshake. In browsers this may result in a dialog appearing + that requests a user to specify the client certificate. + The maximum depth of a certificate chain accepted in verification is Implementation specific. + + Support: Extended + + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to + Kubernetes objects that contain TLS certificates of + the Certificate Authorities that can be used + as a trust anchor to validate the certificates presented by the client. + + A single CA certificate reference to a Kubernetes ConfigMap + has "Core" support. + Implementations MAY choose to support attaching multiple CA certificates to + a Listener, but this behavior is implementation-specific. + + Support: Core - A single reference to a Kubernetes ConfigMap + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one reference, or other kinds + of resources). + + References to a resource in a different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + items: + description: |- + ObjectReference identifies an API object including its namespace. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "ConfigMap" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + minItems: 1 + type: array + type: object + mode: + default: Terminate + description: |- + Mode defines the TLS behavior for the TLS session initiated by the client. + There are two possible modes: + + - Terminate: The TLS session between the downstream client and the + Gateway is terminated at the Gateway. This mode requires certificates + to be specified in some way, such as populating the certificateRefs + field. + - Passthrough: The TLS session is NOT terminated by the Gateway. This + implies that the Gateway can't decipher the TLS stream except for + the ClientHello message of the TLS protocol. The certificateRefs field + is ignored in this mode. + + Support: Core + enum: + - Terminate + - Passthrough + type: string + options: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Options are a list of key/value pairs to enable extended TLS + configuration for each implementation. For example, configuring the + minimum TLS version or supported cipher suites. + + A set of common keys MAY be defined by the API in the future. To avoid + any ambiguity, implementation-specific definitions MUST use + domain-prefixed names, such as `example.com/my-custom-option`. + Un-prefixed names are reserved for key names defined by Gateway API. + + Support: Implementation-specific + maxProperties: 16 + type: object + type: object + x-kubernetes-validations: + - message: certificateRefs or options must be specified when + mode is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 || size(self.options) > 0 : true' + required: + - name + - port + - protocol + type: object + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must not be specified for protocols ['HTTP', 'TCP', + 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: tls mode must be Terminate for protocol HTTPS + rule: 'self.all(l, (l.protocol == ''HTTPS'' && has(l.tls)) ? (l.tls.mode + == '''' || l.tls.mode == ''Terminate'') : true)' + - message: hostname must not be specified for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' + required: + - gatewayClassName + - listeners + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: Status defines the current state of Gateway. + properties: + addresses: + description: |+ + Addresses lists the network addresses that have been bound to the + Gateway. + + This list may differ from the addresses provided in the spec under some + conditions: + + * no addresses are specified, all addresses are dynamically assigned + * a combination of specified and dynamic addresses are assigned + * a specified address was unusable (e.g. already in use) + + items: + description: GatewayStatusAddress describes a network address that + is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: |- + Conditions describe the current conditions of the Gateway. + + Implementations should prefer to express Gateway conditions + using the `GatewayConditionType` and `GatewayConditionReason` + constants so that operators and tools can converge on a common + vocabulary to describe Gateway state. + + Known condition types are: + + * "Accepted" + * "Programmed" + * "Ready" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + listeners: + description: Listeners provide status for each unique listener port + defined in the Spec. + items: + description: ListenerStatus is the status associated with a Listener. + properties: + attachedRoutes: + description: |- + AttachedRoutes represents the total number of Routes that have been + successfully attached to this Listener. + + Successful attachment of a Route to a Listener is based solely on the + combination of the AllowedRoutes field on the corresponding Listener + and the Route's ParentRefs field. A Route is successfully attached to + a Listener when it is selected by the Listener's AllowedRoutes field + AND the Route has a valid ParentRef selecting the whole Gateway + resource or a specific Listener as a parent resource (more detail on + attachment semantics can be found in the documentation on the various + Route kinds ParentRefs fields). Listener or Route status does not impact + successful attachment, i.e. the AttachedRoutes field count MUST be set + for Listeners with condition Accepted: false and MUST count successfully + attached Routes that may themselves have Accepted: false conditions. + + Uses for this field include troubleshooting Route attachment and + measuring blast radius/impact of changes to a Listener. + format: int32 + type: integer + conditions: + description: Conditions describe the current condition of this + listener. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: Name is the name of the Listener that this status + corresponds to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + supportedKinds: + description: |- + SupportedKinds is the list indicating the Kinds supported by this + listener. This MUST represent the kinds an implementation supports for + that Listener configuration. + + If kinds are specified in Spec that are not supported, they MUST NOT + appear in this list and an implementation MUST set the "ResolvedRefs" + condition to "False" with the "InvalidRouteKinds" reason. If both valid + and invalid Route kinds are specified, the implementation MUST + reference the valid Route kinds that have been specified. + items: + description: RouteGroupKind indicates the group and kind of + a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + required: + - attachedRoutes + - conditions + - name + - supportedKinds + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.gatewayClassName + name: Class + type: string + - jsonPath: .status.addresses[*].value + name: Address + type: string + - jsonPath: .status.conditions[?(@.type=="Programmed")].status + name: Programmed + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + Gateway represents an instance of a service-traffic handling infrastructure + by binding Listeners to a set of IP addresses. + 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: + description: Spec defines the desired state of Gateway. + properties: + addresses: + description: |+ + Addresses requested for this Gateway. This is optional and behavior can + depend on the implementation. If a value is set in the spec and the + requested address is invalid or unavailable, the implementation MUST + indicate this in the associated entry in GatewayStatus.Addresses. + + The Addresses field represents a request for the address(es) on the + "outside of the Gateway", that traffic bound for this Gateway will use. + This could be the IP address or hostname of an external load balancer or + other networking infrastructure, or some other address that traffic will + be sent to. + + If no Addresses are specified, the implementation MAY schedule the + Gateway in an implementation-specific manner, assigning an appropriate + set of Addresses. + + The implementation MUST bind all Listeners to every GatewayAddress that + it assigns to the Gateway and add a corresponding entry in + GatewayStatus.Addresses. + + Support: Extended + + items: + description: GatewayAddress describes an address that can be bound + to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: IPAddress values must be unique + rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + - message: Hostname values must be unique + rule: 'self.all(a1, a1.type == ''Hostname'' ? self.exists_one(a2, + a2.type == a1.type && a2.value == a1.value) : true )' + backendTLS: + description: |+ + BackendTLS configures TLS settings for when this Gateway is connecting to + backends with TLS. + + Support: Core + + properties: + clientCertificateRef: + description: |+ + ClientCertificateRef is a reference to an object that contains a Client + Certificate and the associated private key. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + ClientCertificateRef can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + This setting can be overridden on the service level by use of BackendTLSPolicy. + + Support: Core + + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + gatewayClassName: + description: |- + GatewayClassName used for this Gateway. This is the name of a + GatewayClass resource. + maxLength: 253 + minLength: 1 + type: string + infrastructure: + description: |- + Infrastructure defines infrastructure level attributes about this Gateway instance. + + Support: Extended + properties: + annotations: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Annotations that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.annotations` field on resources. + For other implementations, this refers to any relevant (implementation specific) "annotations" concepts. + + An implementation may chose to add additional implementation-specific annotations as they see fit. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Annotation keys must be in the form of an optional + DNS subdomain prefix followed by a required name segment of + up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the annotation key's prefix must be a + DNS subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + labels: + additionalProperties: + description: |- + LabelValue is the value of a label in the Gateway API. This is used for validation + of maps such as Gateway infrastructure labels. This matches the Kubernetes + label validation rules: + * must be 63 characters or less (can be empty), + * unless empty, must begin and end with an alphanumeric character ([a-z0-9A-Z]), + * could contain dashes (-), underscores (_), dots (.), and alphanumerics between. + + Valid values include: + + * MyValue + * my.name + * 123-my-value + maxLength: 63 + minLength: 0 + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + description: |- + Labels that SHOULD be applied to any resources created in response to this Gateway. + + For implementations creating other Kubernetes objects, this should be the `metadata.labels` field on resources. + For other implementations, this refers to any relevant (implementation specific) "labels" concepts. + + An implementation may chose to add additional implementation-specific labels as they see fit. + + If an implementation maps these labels to Pods, or any other resource that would need to be recreated when labels + change, it SHOULD clearly warn about this behavior in documentation. + + Support: Extended + maxProperties: 8 + type: object + x-kubernetes-validations: + - message: Label keys must be in the form of an optional DNS subdomain + prefix followed by a required name segment of up to 63 characters. + rule: self.all(key, key.matches(r"""^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9]$""")) + - message: If specified, the label key's prefix must be a DNS + subdomain not longer than 253 characters in total. + rule: self.all(key, key.split("/")[0].size() < 253) + parametersRef: + description: |- + ParametersRef is a reference to a resource that contains the configuration + parameters corresponding to the Gateway. This is optional if the + controller does not require any additional configuration. + + This follows the same semantics as GatewayClass's `parametersRef`, but on a per-Gateway basis + + The Gateway's GatewayClass may provide its own `parametersRef`. When both are specified, + the merging behavior is implementation specific. + It is generally recommended that GatewayClass provides defaults that can be overridden by a Gateway. + + Support: Implementation-specific + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + type: object + listeners: + description: |- + Listeners associated with this Gateway. Listeners define + logical endpoints that are bound on this Gateway's addresses. + At least one Listener MUST be specified. + + Each Listener in a set of Listeners (for example, in a single Gateway) + MUST be _distinct_, in that a traffic flow MUST be able to be assigned to + exactly one listener. (This section uses "set of Listeners" rather than + "Listeners in a single Gateway" because implementations MAY merge configuration + from multiple Gateways onto a single data plane, and these rules _also_ + apply in that case). + + Practically, this means that each listener in a set MUST have a unique + combination of Port, Protocol, and, if supported by the protocol, Hostname. + + Some combinations of port, protocol, and TLS settings are considered + Core support and MUST be supported by implementations based on their + targeted conformance profile: + + HTTP Profile + + 1. HTTPRoute, Port: 80, Protocol: HTTP + 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: Terminate, TLS keypair provided + + TLS Profile + + 1. TLSRoute, Port: 443, Protocol: TLS, TLS Mode: Passthrough + + "Distinct" Listeners have the following property: + + The implementation can match inbound requests to a single distinct + Listener. When multiple Listeners share values for fields (for + example, two Listeners with the same Port value), the implementation + can match requests to only one of the Listeners using other + Listener fields. + + For example, the following Listener scenarios are distinct: + + 1. Multiple Listeners with the same Port that all use the "HTTP" + Protocol that all have unique Hostname values. + 2. Multiple Listeners with the same Port that use either the "HTTPS" or + "TLS" Protocol that all have unique Hostname values. + 3. A mixture of "TCP" and "UDP" Protocol Listeners, where no Listener + with the same Protocol has the same Port value. + + Some fields in the Listener struct have possible values that affect + whether the Listener is distinct. Hostname is particularly relevant + for HTTP or HTTPS protocols. + + When using the Hostname value to select between same-Port, same-Protocol + Listeners, the Hostname value must be different on each Listener for the + Listener to be distinct. + + When the Listeners are distinct based on Hostname, inbound request + hostnames MUST match from the most specific to least specific Hostname + values to choose the correct Listener and its associated set of Routes. + + Exact matches must be processed before wildcard matches, and wildcard + matches must be processed before fallback (empty Hostname value) + matches. For example, `"foo.example.com"` takes precedence over + `"*.example.com"`, and `"*.example.com"` takes precedence over `""`. + + Additionally, if there are multiple wildcard entries, more specific + wildcard entries must be processed before less specific wildcard entries. + For example, `"*.foo.example.com"` takes precedence over `"*.example.com"`. + The precise definition here is that the higher the number of dots in the + hostname to the right of the wildcard character, the higher the precedence. + + The wildcard character will match any number of characters _and dots_ to + the left, however, so `"*.example.com"` will match both + `"foo.bar.example.com"` _and_ `"bar.example.com"`. + + If a set of Listeners contains Listeners that are not distinct, then those + Listeners are Conflicted, and the implementation MUST set the "Conflicted" + condition in the Listener Status to "True". + + Implementations MAY choose to accept a Gateway with some Conflicted + Listeners only if they only accept the partial Listener set that contains + no Conflicted Listeners. To put this another way, implementations may + accept a partial Listener set only if they throw out *all* the conflicting + Listeners. No picking one of the conflicting listeners as the winner. + This also means that the Gateway must have at least one non-conflicting + Listener in this case, otherwise it violates the requirement that at + least one Listener must be present. + + The implementation MUST set a "ListenersNotValid" condition on the + Gateway Status when the Gateway contains Conflicted Listeners whether or + not they accept the Gateway. That Condition SHOULD clearly + indicate in the Message which Listeners are conflicted, and which are + Accepted. Additionally, the Listener status for those listeners SHOULD + indicate which Listeners are conflicted and not Accepted. + + A Gateway's Listeners are considered "compatible" if: + + 1. They are distinct. + 2. The implementation can serve them in compliance with the Addresses + requirement that all Listeners are available on all assigned + addresses. + + Compatible combinations in Extended support are expected to vary across + implementations. A combination that is compatible for one implementation + may not be compatible for another. + + For example, an implementation that cannot serve both TCP and UDP listeners + on the same address, or cannot mix HTTPS and generic TLS listens on the same port + would not consider those cases compatible, even though they are distinct. + + Note that requests SHOULD match at most one Listener. For example, if + Listeners are defined for "foo.example.com" and "*.example.com", a + request to "foo.example.com" SHOULD only be routed using routes attached + to the "foo.example.com" Listener (and not the "*.example.com" Listener). + This concept is known as "Listener Isolation". Implementations that do + not support Listener Isolation MUST clearly document this. + + Implementations MAY merge separate Gateways onto a single set of + Addresses if all Listeners across all Gateways are compatible. + + Support: Core + items: + description: |- + Listener embodies the concept of a logical endpoint where a Gateway accepts + network connections. + properties: + allowedRoutes: + default: + namespaces: + from: Same + description: |- + AllowedRoutes defines the types of routes that MAY be attached to a + Listener and the trusted namespaces where those Route resources MAY be + present. + + Although a client request may match multiple route rules, only one rule + may ultimately receive the request. Matching precedence MUST be + determined in order of the following criteria: + + * The most specific match as defined by the Route type. + * The oldest Route based on creation timestamp. For example, a Route with + a creation timestamp of "2020-09-08 01:02:03" is given precedence over + a Route with a creation timestamp of "2020-09-08 01:02:04". + * If everything else is equivalent, the Route appearing first in + alphabetical order (namespace/name) should be given precedence. For + example, foo/bar is given precedence over foo/baz. + + All valid rules within a Route attached to this Listener should be + implemented. Invalid Route rules can be ignored (sometimes that will mean + the full Route). If a Route rule transitions from valid to invalid, + support for that Route rule should be dropped to ensure consistency. For + example, even if a filter specified by a Route rule is invalid, the rest + of the rules within that Route should still be supported. + + Support: Core + properties: + kinds: + description: |- + Kinds specifies the groups and kinds of Routes that are allowed to bind + to this Gateway Listener. When unspecified or empty, the kinds of Routes + selected are determined using the Listener protocol. + + A RouteGroupKind MUST correspond to kinds of Routes that are compatible + with the application protocol specified in the Listener's Protocol field. + If an implementation does not support or recognize this resource type, it + MUST set the "ResolvedRefs" condition to False for this Listener with the + "InvalidRouteKinds" reason. + + Support: Core + items: + description: RouteGroupKind indicates the group and kind + of a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + namespaces: + default: + from: Same + description: |- + Namespaces indicates namespaces from which Routes may be attached to this + Listener. This is restricted to the namespace of this Gateway by default. + + Support: Core + properties: + from: + default: Same + description: |- + From indicates where Routes will be selected for this Gateway. Possible + values are: + + * All: Routes in all namespaces may be used by this Gateway. + * Selector: Routes in namespaces selected by the selector may be used by + this Gateway. + * Same: Only Routes in the same namespace may be used by this Gateway. + + Support: Core + enum: + - All + - Selector + - Same + type: string + selector: + description: |- + Selector must be specified when From is set to "Selector". In that case, + only Routes in Namespaces matching this Selector will be selected by this + Gateway. This field is ignored for other values of "From". + + Support: Core + 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 + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + 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 + x-kubernetes-map-type: atomic + type: object + type: object + hostname: + description: |- + Hostname specifies the virtual hostname to match for protocol types that + define this concept. When unspecified, all hostnames are matched. This + field is ignored for protocols that don't require hostname based + matching. + + Implementations MUST apply Hostname matching appropriately for each of + the following protocols: + + * TLS: The Listener Hostname MUST match the SNI. + * HTTP: The Listener Hostname MUST match the Host header of the request. + * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP + protocol layers as described above. If an implementation does not + ensure that both the SNI and Host header match the Listener hostname, + it MUST clearly document that. + + For HTTPRoute and TLSRoute resources, there is an interaction with the + `spec.hostnames` array. When both listener and route specify hostnames, + there MUST be an intersection between the values for a Route to be + accepted. For more information, refer to the Route specific Hostnames + documentation. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + name: + description: |- + Name is the name of the Listener. This name MUST be unique within a + Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: |- + Port is the network port. Multiple listeners may use the + same port, subject to the Listener compatibility rules. + + Support: Core + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: |- + Protocol specifies the network protocol this listener expects to receive. + + Support: Core + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ + type: string + tls: + description: |- + TLS is the TLS configuration for the Listener. This field is required if + the Protocol field is "HTTPS" or "TLS". It is invalid to set this field + if the Protocol field is "HTTP", "TCP", or "UDP". + + The association of SNIs to Certificate defined in GatewayTLSConfig is + defined based on the Hostname field for this listener. + + The GatewayClass MUST use the longest matching SNI out of all + available certificates for any TLS handshake. + + Support: Core + properties: + certificateRefs: + description: |- + CertificateRefs contains a series of references to Kubernetes objects that + contains TLS certificates and private keys. These certificates are used to + establish a TLS handshake for requests that match the hostname of the + associated listener. + + A single CertificateRef to a Kubernetes Secret has "Core" support. + Implementations MAY choose to support attaching multiple certificates to + a Listener, but this behavior is implementation-specific. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + This field is required to have at least one element when the mode is set + to "Terminate" (default) and is optional otherwise. + + CertificateRefs can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls + + Support: Implementation-specific (More than one reference or other resource types) + items: + description: |- + SecretObjectReference identifies an API object including its namespace, + defaulting to Secret. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + maxItems: 64 + type: array + frontendValidation: + description: |+ + FrontendValidation holds configuration information for validating the frontend (client). + Setting this field will require clients to send a client certificate + required for validation during the TLS handshake. In browsers this may result in a dialog appearing + that requests a user to specify the client certificate. + The maximum depth of a certificate chain accepted in verification is Implementation specific. + + Support: Extended + + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to + Kubernetes objects that contain TLS certificates of + the Certificate Authorities that can be used + as a trust anchor to validate the certificates presented by the client. + + A single CA certificate reference to a Kubernetes ConfigMap + has "Core" support. + Implementations MAY choose to support attaching multiple CA certificates to + a Listener, but this behavior is implementation-specific. + + Support: Core - A single reference to a Kubernetes ConfigMap + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one reference, or other kinds + of resources). + + References to a resource in a different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + items: + description: |- + ObjectReference identifies an API object including its namespace. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "ConfigMap" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + minItems: 1 + type: array + type: object + mode: + default: Terminate + description: |- + Mode defines the TLS behavior for the TLS session initiated by the client. + There are two possible modes: + + - Terminate: The TLS session between the downstream client and the + Gateway is terminated at the Gateway. This mode requires certificates + to be specified in some way, such as populating the certificateRefs + field. + - Passthrough: The TLS session is NOT terminated by the Gateway. This + implies that the Gateway can't decipher the TLS stream except for + the ClientHello message of the TLS protocol. The certificateRefs field + is ignored in this mode. + + Support: Core + enum: + - Terminate + - Passthrough + type: string + options: + additionalProperties: + description: |- + AnnotationValue is the value of an annotation in Gateway API. This is used + for validation of maps such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation in that case is based + on the entire size of the annotations struct. + maxLength: 4096 + minLength: 0 + type: string + description: |- + Options are a list of key/value pairs to enable extended TLS + configuration for each implementation. For example, configuring the + minimum TLS version or supported cipher suites. + + A set of common keys MAY be defined by the API in the future. To avoid + any ambiguity, implementation-specific definitions MUST use + domain-prefixed names, such as `example.com/my-custom-option`. + Un-prefixed names are reserved for key names defined by Gateway API. + + Support: Implementation-specific + maxProperties: 16 + type: object + type: object + x-kubernetes-validations: + - message: certificateRefs or options must be specified when + mode is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 0 || size(self.options) > 0 : true' + required: + - name + - port + - protocol + type: object + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: tls must not be specified for protocols ['HTTP', 'TCP', + 'UDP'] + rule: 'self.all(l, l.protocol in [''HTTP'', ''TCP'', ''UDP''] ? + !has(l.tls) : true)' + - message: tls mode must be Terminate for protocol HTTPS + rule: 'self.all(l, (l.protocol == ''HTTPS'' && has(l.tls)) ? (l.tls.mode + == '''' || l.tls.mode == ''Terminate'') : true)' + - message: hostname must not be specified for protocols ['TCP', 'UDP'] + rule: 'self.all(l, l.protocol in [''TCP'', ''UDP''] ? (!has(l.hostname) + || l.hostname == '''') : true)' + - message: Listener name must be unique within the Gateway + rule: self.all(l1, self.exists_one(l2, l1.name == l2.name)) + - message: Combination of port, protocol and hostname must be unique + for each listener + rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol + == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname + == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' + required: + - gatewayClassName + - listeners + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: Status defines the current state of Gateway. + properties: + addresses: + description: |+ + Addresses lists the network addresses that have been bound to the + Gateway. + + This list may differ from the addresses provided in the spec under some + conditions: + + * no addresses are specified, all addresses are dynamically assigned + * a combination of specified and dynamic addresses are assigned + * a specified address was unusable (e.g. already in use) + + items: + description: GatewayStatusAddress describes a network address that + is bound to a Gateway. + oneOf: + - properties: + type: + enum: + - IPAddress + value: + anyOf: + - format: ipv4 + - format: ipv6 + - properties: + type: + not: + enum: + - IPAddress + properties: + type: + default: IPAddress + description: Type of the address. + maxLength: 253 + minLength: 1 + pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + value: + description: |- + Value of the address. The validity of the values will depend + on the type and support by the controller. + + Examples: `1.2.3.4`, `128::1`, `my-ip-address`. + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + x-kubernetes-validations: + - message: Hostname value must only contain valid characters (matching + ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$) + rule: 'self.type == ''Hostname'' ? self.value.matches(r"""^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"""): + true' + maxItems: 16 + type: array + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Accepted + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: |- + Conditions describe the current conditions of the Gateway. + + Implementations should prefer to express Gateway conditions + using the `GatewayConditionType` and `GatewayConditionReason` + constants so that operators and tools can converge on a common + vocabulary to describe Gateway state. + + Known condition types are: + + * "Accepted" + * "Programmed" + * "Ready" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + listeners: + description: Listeners provide status for each unique listener port + defined in the Spec. + items: + description: ListenerStatus is the status associated with a Listener. + properties: + attachedRoutes: + description: |- + AttachedRoutes represents the total number of Routes that have been + successfully attached to this Listener. + + Successful attachment of a Route to a Listener is based solely on the + combination of the AllowedRoutes field on the corresponding Listener + and the Route's ParentRefs field. A Route is successfully attached to + a Listener when it is selected by the Listener's AllowedRoutes field + AND the Route has a valid ParentRef selecting the whole Gateway + resource or a specific Listener as a parent resource (more detail on + attachment semantics can be found in the documentation on the various + Route kinds ParentRefs fields). Listener or Route status does not impact + successful attachment, i.e. the AttachedRoutes field count MUST be set + for Listeners with condition Accepted: false and MUST count successfully + attached Routes that may themselves have Accepted: false conditions. + + Uses for this field include troubleshooting Route attachment and + measuring blast radius/impact of changes to a Listener. + format: int32 + type: integer + conditions: + description: Conditions describe the current condition of this + listener. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: Name is the name of the Listener that this status + corresponds to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + supportedKinds: + description: |- + SupportedKinds is the list indicating the Kinds supported by this + listener. This MUST represent the kinds an implementation supports for + that Listener configuration. + + If kinds are specified in Spec that are not supported, they MUST NOT + appear in this list and an implementation MUST set the "ResolvedRefs" + condition to "False" with the "InvalidRouteKinds" reason. If both valid + and invalid Route kinds are specified, the implementation MUST + reference the valid Route kinds that have been specified. + items: + description: RouteGroupKind indicates the group and kind of + a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + required: + - attachedRoutes + - conditions + - name + - supportedKinds + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: grpcroutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: GRPCRoute + listKind: GRPCRouteList + plural: grpcroutes + singular: grpcroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + GRPCRoute provides a way to route gRPC requests. This includes the capability + to match requests by hostname, gRPC service, gRPC method, or HTTP/2 header. + Filters can be used to specify additional processing steps. Backends specify + where matching requests will be routed. + + GRPCRoute falls under extended support within the Gateway API. Within the + following specification, the word "MUST" indicates that an implementation + supporting GRPCRoute must conform to the indicated requirement, but an + implementation not supporting this route type need not follow the requirement + unless explicitly indicated. + + Implementations supporting `GRPCRoute` with the `HTTPS` `ProtocolType` MUST + accept HTTP/2 connections without an initial upgrade from HTTP/1.1, i.e. via + ALPN. If the implementation does not support this, then it MUST set the + "Accepted" condition to "False" for the affected listener with a reason of + "UnsupportedProtocol". Implementations MAY also accept HTTP/2 connections + with an upgrade from HTTP/1. + + Implementations supporting `GRPCRoute` with the `HTTP` `ProtocolType` MUST + support HTTP/2 over cleartext TCP (h2c, + https://www.rfc-editor.org/rfc/rfc7540#section-3.1) without an initial + upgrade from HTTP/1.1, i.e. with prior knowledge + (https://www.rfc-editor.org/rfc/rfc7540#section-3.4). If the implementation + does not support this, then it MUST set the "Accepted" condition to "False" + for the affected listener with a reason of "UnsupportedProtocol". + Implementations MAY also accept HTTP/2 connections with an upgrade from + HTTP/1, i.e. without prior knowledge. + 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: + description: Spec defines the desired state of GRPCRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames to match against the GRPC + Host header to select a GRPCRoute to process the request. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label MUST appear by itself as the first label. + + If a hostname is specified by both the Listener and GRPCRoute, there + MUST be at least one intersecting hostname for the GRPCRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches GRPCRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches GRPCRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `test.example.com` and `*.example.com` would both match. On the other + hand, `example.com` and `test.example.net` would not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and GRPCRoute have specified hostnames, any + GRPCRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + GRPCRoute specified `test.example.com` and `test.example.net`, + `test.example.net` MUST NOT be considered for a match. + + If both the Listener and GRPCRoute have specified hostnames, and none + match with the criteria above, then the GRPCRoute MUST NOT be accepted by + the implementation. The implementation MUST raise an 'Accepted' Condition + with a status of `False` in the corresponding RouteParentStatus. + + If a Route (A) of type HTTPRoute or GRPCRoute is attached to a + Listener and that listener already has another Route (B) of the other + type attached and the intersection of the hostnames of A and B is + non-empty, then the implementation MUST accept exactly one of these two + routes, determined by the following criteria, in order: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + The rejected Route MUST raise an 'Accepted' condition with a status of + 'False' in the corresponding RouteParentStatus. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + description: |+ + Rules are a list of GRPC matchers, filters and actions. + + items: + description: |- + GRPCRouteRule defines the semantics for matching a gRPC request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive an `UNAVAILABLE` status. + + See the GRPCBackendRef definition for the rules about what makes a single + GRPCBackendRef invalid. + + When a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive an `UNAVAILABLE` status. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status. + Implementations may choose how that 50 percent is determined. + + Support: Core for Kubernetes Service + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + GRPCBackendRef defines how a GRPCRoute forwards a gRPC request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + <gateway:experimental:description> + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + </gateway:experimental:description> + properties: + filters: + description: |- + Filters defined at this level MUST be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in GRPCRouteRule.) + items: + description: |- + GRPCRouteFilter defines processing steps that must be completed during the + request or response lifecycle. GRPCRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + Support: Implementation-specific + + This filter can be used multiple times within the same rule. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |+ + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations supporting GRPCRoute MUST support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` MUST be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + enum: + - ResponseHeaderModifier + - RequestHeaderModifier + - RequestMirror + - ExtensionRef + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + The effects of ordering of multiple behaviors are currently unspecified. + This can change in the future based on feedback during the alpha stage. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations that support + GRPCRoute. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + If an implementation can not support a combination of filters, it must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + GRPCRouteFilter defines processing steps that must be completed during the + request or response lifecycle. GRPCRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + Support: Implementation-specific + + This filter can be used multiple times within the same rule. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |+ + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations supporting GRPCRoute MUST support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` MUST be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + enum: + - ResponseHeaderModifier + - RequestHeaderModifier + - RequestMirror + - ExtensionRef + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + matches: + description: |- + Matches define conditions used for matching the rule against incoming + gRPC requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - method: + service: foo.bar + headers: + values: + version: 2 + - method: + service: foo.bar.v2 + ``` + + For a request to match against this rule, it MUST satisfy + EITHER of the two conditions: + + - service of foo.bar AND contains the header `version: 2` + - service of foo.bar.v2 + + See the documentation for GRPCRouteMatch on how to specify multiple + match conditions to be ANDed together. + + If no matches are specified, the implementation MUST match every gRPC request. + + Proxy or Load Balancer routing configuration generated from GRPCRoutes + MUST prioritize rules based on the following criteria, continuing on + ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes. + Precedence MUST be given to the rule with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + * Characters in a matching service. + * Characters in a matching method. + * Header matches. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within the Route that has been given precedence, + matching precedence MUST be granted to the first matching rule meeting + the above criteria. + items: + description: |- + GRPCRouteMatch defines the predicate used to match requests to a given + action. Multiple match types are ANDed together, i.e. the match will + evaluate to true only if all conditions are satisfied. + + For example, the match below will match a gRPC request only if its service + is `foo` AND it contains the `version: v1` header: + + ``` + matches: + - method: + type: Exact + service: "foo" + headers: + - name: "version" + value "v1" + + ``` + properties: + headers: + description: |- + Headers specifies gRPC request header matchers. Multiple match values are + ANDed together, meaning, a request MUST match all the specified headers + to select the route. + items: + description: |- + GRPCHeaderMatch describes how to select a gRPC route by matching gRPC request + headers. + properties: + name: + description: |- + Name is the name of the gRPC Header to be matched. + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: Type specifies how to match against + the value of the header. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of the gRPC Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies a gRPC request service/method matcher. If this field is + not specified, all services and methods will match. + properties: + method: + description: |- + Value of the method to match against. If left empty or omitted, will + match all services. + + At least one of Service and Method MUST be a non-empty string. + maxLength: 1024 + type: string + service: + description: |- + Value of the service to match against. If left empty or omitted, will + match any service. + + At least one of Service and Method MUST be a non-empty string. + maxLength: 1024 + type: string + type: + default: Exact + description: |- + Type specifies how to match against the service and/or method. + Support: Core (Exact with service and method specified) + + Support: Implementation-specific (Exact with method specified but no service specified) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - RegularExpression + type: string + type: object + x-kubernetes-validations: + - message: One or both of 'service' or 'method' must be + specified + rule: 'has(self.type) ? has(self.service) || has(self.method) + : true' + - message: service must only contain valid characters + (matching ^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$) + rule: '(!has(self.type) || self.type == ''Exact'') && + has(self.service) ? self.service.matches(r"""^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$"""): + true' + - message: method must only contain valid characters (matching + ^[A-Za-z_][A-Za-z_0-9]*$) + rule: '(!has(self.type) || self.type == ''Exact'') && + has(self.method) ? self.method.matches(r"""^[A-Za-z_][A-Za-z_0-9]*$"""): + true' + type: object + maxItems: 8 + type: array + name: + description: | + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + sessionPersistence: + description: |+ + SessionPersistence defines and configures session persistence + for the route rule. + + Support: Extended + + properties: + absoluteTimeout: + description: |- + AbsoluteTimeout defines the absolute timeout of the persistent + session. Once the AbsoluteTimeout duration has elapsed, the + session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + cookieConfig: + description: |- + CookieConfig provides configuration settings that are specific + to cookie-based session persistence. + + Support: Core + properties: + lifetimeType: + default: Session + description: |- + LifetimeType specifies whether the cookie has a permanent or + session-based lifetime. A permanent cookie persists until its + specified expiry time, defined by the Expires or Max-Age cookie + attributes, while a session cookie is deleted when the current + session ends. + + When set to "Permanent", AbsoluteTimeout indicates the + cookie's lifetime via the Expires or Max-Age cookie attributes + and is required. + + When set to "Session", AbsoluteTimeout indicates the + absolute lifetime of the cookie tracked by the gateway and + is optional. + + Support: Core for "Session" type + + Support: Extended for "Permanent" type + enum: + - Permanent + - Session + type: string + type: object + idleTimeout: + description: |- + IdleTimeout defines the idle timeout of the persistent session. + Once the session has been idle for more than the specified + IdleTimeout duration, the session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + sessionName: + description: |- + SessionName defines the name of the persistent session token + which may be reflected in the cookie or the header. Users + should avoid reusing session names to prevent unintended + consequences, such as rejection or unpredictable behavior. + + Support: Implementation-specific + maxLength: 128 + type: string + type: + default: Cookie + description: |- + Type defines the type of session persistence such as through + the use a header or cookie. Defaults to cookie based session + persistence. + + Support: Core for "Cookie" type + + Support: Extended for "Header" type + enum: + - Cookie + - Header + type: string + type: object + x-kubernetes-validations: + - message: AbsoluteTimeout must be specified when cookie lifetimeType + is Permanent + rule: '!has(self.cookieConfig) || !has(self.cookieConfig.lifetimeType) + || self.cookieConfig.lifetimeType != ''Permanent'' || has(self.absoluteTimeout)' + type: object + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? (has(self[0].matches) ? self[0].matches.size() + : 0) : 0) + (self.size() > 1 ? (has(self[1].matches) ? self[1].matches.size() + : 0) : 0) + (self.size() > 2 ? (has(self[2].matches) ? self[2].matches.size() + : 0) : 0) + (self.size() > 3 ? (has(self[3].matches) ? self[3].matches.size() + : 0) : 0) + (self.size() > 4 ? (has(self[4].matches) ? self[4].matches.size() + : 0) : 0) + (self.size() > 5 ? (has(self[5].matches) ? self[5].matches.size() + : 0) : 0) + (self.size() > 6 ? (has(self[6].matches) ? self[6].matches.size() + : 0) : 0) + (self.size() > 7 ? (has(self[7].matches) ? self[7].matches.size() + : 0) : 0) + (self.size() > 8 ? (has(self[8].matches) ? self[8].matches.size() + : 0) : 0) + (self.size() > 9 ? (has(self[9].matches) ? self[9].matches.size() + : 0) : 0) + (self.size() > 10 ? (has(self[10].matches) ? self[10].matches.size() + : 0) : 0) + (self.size() > 11 ? (has(self[11].matches) ? self[11].matches.size() + : 0) : 0) + (self.size() > 12 ? (has(self[12].matches) ? self[12].matches.size() + : 0) : 0) + (self.size() > 13 ? (has(self[13].matches) ? self[13].matches.size() + : 0) : 0) + (self.size() > 14 ? (has(self[14].matches) ? self[14].matches.size() + : 0) : 0) + (self.size() > 15 ? (has(self[15].matches) ? self[15].matches.size() + : 0) : 0) <= 128' + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + type: object + status: + description: Status defines the current state of GRPCRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: httproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: HTTPRoute + listKind: HTTPRouteList + plural: httproutes + singular: httproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + HTTPRoute provides a way to route HTTP requests. This includes the capability + to match requests by hostname, path, header, or query param. Filters can be + used to specify additional processing steps. Backends specify where matching + requests should be routed. + 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: + description: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames that should match against the HTTP Host + header to select a HTTPRoute used to process the request. Implementations + MUST ignore any port value specified in the HTTP Host header while + performing a match and (absent of any applicable header modification + configuration) MUST forward this header unmodified to the backend. + + Valid values for Hostnames are determined by RFC 1123 definition of a + hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and HTTPRoute, there + must be at least one intersecting hostname for the HTTPRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `*.example.com`, `test.example.com`, and `foo.test.example.com` would + all match. On the other hand, `example.com` and `test.example.net` would + not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and HTTPRoute have specified hostnames, any + HTTPRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and HTTPRoute have specified hostnames, and none + match with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. + overlapping wildcard matching and exact matching hostnames), precedence must + be given to rules from the HTTPRoute with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + + If ties exist across multiple Routes, the matching precedence rules for + HTTPRouteMatches takes over. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: + description: |- + HTTPRouteRule defines semantics for matching an HTTP request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive a 500 status code. + + See the HTTPBackendRef definition for the rules about what makes a single + HTTPBackendRef invalid. + + When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive a 500 status code. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic must receive a 500. Implementations may + choose how that 50 percent is determined. + + When a HTTPBackendRef refers to a Service that has no ready endpoints, + implementations SHOULD return a 503 for requests to that backend instead. + If an implementation chooses to do this, all of the above rules for 500 responses + MUST also apply for responses that return a 503. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + <gateway:experimental:description> + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + </gateway:experimental:description> + properties: + filters: + description: |- + Filters defined at this level should be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in HTTPRouteRule.) + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() + <= 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + Wherever possible, implementations SHOULD implement filters in the order + they are specified. + + Implementations MAY choose to implement this ordering strictly, rejecting + any combination or order of filters that can not be supported. If implementations + choose a strict interpretation of filter ordering, they MUST clearly document + that behavior. + + To reject an invalid combination or order of filters, implementations SHOULD + consider the Route Rules with this configuration invalid. If all Route Rules + in a Route are invalid, the entire Route would be considered invalid. If only + a portion of Route Rules are invalid, implementations MUST set the + "PartiallyInvalid" condition for the Route. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() <= + 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() <= 1 + matches: + default: + - path: + type: PathPrefix + value: / + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + Note: The precedence of RegularExpression path matches are implementation-specific. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given\naction. Multiple match types + are ANDed together, i.e. the match will\nevaluate to true + only if all conditions are satisfied.\n\nFor example, the + match below will match a HTTP request only if its path\nstarts + with `/foo` AND it contains the `version: v1` header:\n\n```\nmatch:\n\n\tpath:\n\t + \ value: \"/foo\"\n\theaders:\n\t- name: \"version\"\n\t + \ value \"v1\"\n\n```" + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies HTTP method matcher. + When specified, this route will be matched only if the request has the + specified method. + + Support: Extended + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: |- + Path specifies a HTTP request path matcher. If this field is not + specified, a default prefix match on the "/" path is provided. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.startsWith(''/'') + : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''//'') + : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/./'') + : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/../'') + : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2f'') + : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2F'') + : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''#'') + : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/..'') + : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/.'') + : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type in ['Exact','PathPrefix'] || self.type + == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + Support: Extended (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 64 + type: array + name: + description: | + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + retry: + description: |+ + Retry defines the configuration for when to retry an HTTP request. + + Support: Extended + + properties: + attempts: + description: |- + Attempts specifies the maxmimum number of times an individual request + from the gateway to a backend should be retried. + + If the maximum number of retries has been attempted without a successful + response from the backend, the Gateway MUST return an error. + + When this field is unspecified, the number of times to attempt to retry + a backend request is implementation-specific. + + Support: Extended + type: integer + backoff: + description: |- + Backoff specifies the minimum duration a Gateway should wait between + retry attempts and is represented in Gateway API Duration formatting. + + For example, setting the `rules[].retry.backoff` field to the value + `100ms` will cause a backend request to first be retried approximately + 100 milliseconds after timing out or receiving a response code configured + to be retryable. + + An implementation MAY use an exponential or alternative backoff strategy + for subsequent retry attempts, MAY cap the maximum backoff duration to + some amount greater than the specified minimum, and MAY add arbitrary + jitter to stagger requests, as long as unsuccessful backend requests are + not retried before the configured minimum duration. + + If a Request timeout (`rules[].timeouts.request`) is configured on the + route, the entire duration of the initial request and any retry attempts + MUST not exceed the Request timeout duration. If any retry attempts are + still in progress when the Request timeout duration has been reached, + these SHOULD be canceled if possible and the Gateway MUST immediately + return a timeout error. + + If a BackendRequest timeout (`rules[].timeouts.backendRequest`) is + configured on the route, any retry attempts which reach the configured + BackendRequest timeout duration without a response SHOULD be canceled if + possible and the Gateway should wait for at least the specified backoff + duration before attempting to retry the backend request again. + + If a BackendRequest timeout is _not_ configured on the route, retry + attempts MAY time out after an implementation default duration, or MAY + remain pending until a configured Request timeout or implementation + default duration for total request time is reached. + + When this field is unspecified, the time to wait between retry attempts + is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + codes: + description: |- + Codes defines the HTTP response status codes for which a backend request + should be retried. + + Support: Extended + items: + description: |- + HTTPRouteRetryStatusCode defines an HTTP response status code for + which a backend request should be retried. + + Implementations MUST support the following status codes as retryable: + + * 500 + * 502 + * 503 + * 504 + + Implementations MAY support specifying additional discrete values in the + 500-599 range. + + Implementations MAY support specifying discrete values in the 400-499 range, + which are often inadvisable to retry. + + <gateway:experimental> + maximum: 599 + minimum: 400 + type: integer + type: array + type: object + sessionPersistence: + description: |+ + SessionPersistence defines and configures session persistence + for the route rule. + + Support: Extended + + properties: + absoluteTimeout: + description: |- + AbsoluteTimeout defines the absolute timeout of the persistent + session. Once the AbsoluteTimeout duration has elapsed, the + session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + cookieConfig: + description: |- + CookieConfig provides configuration settings that are specific + to cookie-based session persistence. + + Support: Core + properties: + lifetimeType: + default: Session + description: |- + LifetimeType specifies whether the cookie has a permanent or + session-based lifetime. A permanent cookie persists until its + specified expiry time, defined by the Expires or Max-Age cookie + attributes, while a session cookie is deleted when the current + session ends. + + When set to "Permanent", AbsoluteTimeout indicates the + cookie's lifetime via the Expires or Max-Age cookie attributes + and is required. + + When set to "Session", AbsoluteTimeout indicates the + absolute lifetime of the cookie tracked by the gateway and + is optional. + + Support: Core for "Session" type + + Support: Extended for "Permanent" type + enum: + - Permanent + - Session + type: string + type: object + idleTimeout: + description: |- + IdleTimeout defines the idle timeout of the persistent session. + Once the session has been idle for more than the specified + IdleTimeout duration, the session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + sessionName: + description: |- + SessionName defines the name of the persistent session token + which may be reflected in the cookie or the header. Users + should avoid reusing session names to prevent unintended + consequences, such as rejection or unpredictable behavior. + + Support: Implementation-specific + maxLength: 128 + type: string + type: + default: Cookie + description: |- + Type defines the type of session persistence such as through + the use a header or cookie. Defaults to cookie based session + persistence. + + Support: Core for "Cookie" type + + Support: Extended for "Header" type + enum: + - Cookie + - Header + type: string + type: object + x-kubernetes-validations: + - message: AbsoluteTimeout must be specified when cookie lifetimeType + is Permanent + rule: '!has(self.cookieConfig) || !has(self.cookieConfig.lifetimeType) + || self.cookieConfig.lifetimeType != ''Permanent'' || has(self.absoluteTimeout)' + timeouts: + description: |- + Timeouts defines the timeouts that can be configured for an HTTP request. + + Support: Extended + properties: + backendRequest: + description: |- + BackendRequest specifies a timeout for an individual request from the gateway + to a backend. This covers the time from when the request first starts being + sent from the gateway to when the full response has been received from the backend. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + An entire client HTTP transaction with a gateway, covered by the Request timeout, + may result in more than one call from the gateway to the destination backend, + for example, if automatic retries are supported. + + The value of BackendRequest must be a Gateway API Duration string as defined by + GEP-2257. When this field is unspecified, its behavior is implementation-specific; + when specified, the value of BackendRequest must be no more than the value of the + Request timeout (since the Request timeout encompasses the BackendRequest timeout). + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + request: + description: |- + Request specifies the maximum duration for a gateway to respond to an HTTP request. + If the gateway has not been able to respond before this deadline is met, the gateway + MUST return a timeout error. + + For example, setting the `rules.timeouts.request` field to the value `10s` in an + `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds + to complete. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + This timeout is intended to cover as close to the whole request-response transaction + as possible although an implementation MAY choose to start the timeout after the entire + request stream has been received instead of immediately after the transaction is + initiated by the client. + + The value of Request is a Gateway API Duration string as defined by GEP-2257. When this + field is unspecified, request timeout behavior is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + x-kubernetes-validations: + - message: backendRequest timeout cannot be longer than request + timeout + rule: '!(has(self.request) && has(self.backendRequest) && + duration(self.request) != duration(''0s'') && duration(self.backendRequest) + > duration(self.request))' + type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() + > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() + : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() + > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() + : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() + > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() + : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() + > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() + : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() + > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() + : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + HTTPRoute provides a way to route HTTP requests. This includes the capability + to match requests by hostname, path, header, or query param. Filters can be + used to specify additional processing steps. Backends specify where matching + requests should be routed. + 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: + description: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of hostnames that should match against the HTTP Host + header to select a HTTPRoute used to process the request. Implementations + MUST ignore any port value specified in the HTTP Host header while + performing a match and (absent of any applicable header modification + configuration) MUST forward this header unmodified to the backend. + + Valid values for Hostnames are determined by RFC 1123 definition of a + hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and HTTPRoute, there + must be at least one intersecting hostname for the HTTPRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `*.example.com`, `test.example.com`, and `foo.test.example.com` would + all match. On the other hand, `example.com` and `test.example.net` would + not match. + + Hostnames that are prefixed with a wildcard label (`*.`) are interpreted + as a suffix match. That means that a match for `*.example.com` would match + both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + + If both the Listener and HTTPRoute have specified hostnames, any + HTTPRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and HTTPRoute have specified hostnames, and none + match with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. + overlapping wildcard matching and exact matching hostnames), precedence must + be given to rules from the HTTPRoute with the largest number of: + + * Characters in a matching non-wildcard hostname. + * Characters in a matching hostname. + + If ties exist across multiple Routes, the matching precedence rules for + HTTPRouteMatches takes over. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: + description: |- + HTTPRouteRule defines semantics for matching an HTTP request based on + conditions (matches), processing it (filters), and forwarding the request to + an API object (backendRefs). + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. + + Failure behavior here depends on how many BackendRefs are specified and + how many are invalid. + + If *all* entries in BackendRefs are invalid, and there are also no filters + specified in this route rule, *all* traffic which matches this rule MUST + receive a 500 status code. + + See the HTTPBackendRef definition for the rules about what makes a single + HTTPBackendRef invalid. + + When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + requests that would have otherwise been routed to an invalid backend. If + multiple backends are specified, and some are invalid, the proportion of + requests that would otherwise have been routed to an invalid backend + MUST receive a 500 status code. + + For example, if two backends are specified with equal weights, and one is + invalid, 50 percent of traffic must receive a 500. Implementations may + choose how that 50 percent is determined. + + When a HTTPBackendRef refers to a Service that has no ready endpoints, + implementations SHOULD return a 503 for requests to that backend instead. + If an implementation chooses to do this, all of the above rules for 500 responses + MUST also apply for responses that return a 503. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Core + items: + description: |- + HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + <gateway:experimental:description> + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + </gateway:experimental:description> + properties: + filters: + description: |- + Filters defined at this level should be executed if and only if the + request is being forwarded to the backend defined here. + + Support: Implementation-specific (For broader support of filters, use the + Filters field in HTTPRouteRule.) + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified + when type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? + has(self.replaceFullPath) : true' + - message: type must be 'ReplaceFullPath' when + replaceFullPath is set + rule: 'has(self.replaceFullPath) ? self.type + == ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified + when type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' + ? has(self.replacePrefixMatch) : true' + - message: type must be 'ReplacePrefixMatch' + when replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil + if the filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type + != ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type + == ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil + if the filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type + != ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for + RequestMirror filter.type + rule: '!(!has(self.requestMirror) && self.type == + ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the + filter.type is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != + ''RequestRedirect'')' + - message: filter.requestRedirect must be specified + for RequestRedirect filter.type + rule: '!(!has(self.requestRedirect) && self.type == + ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for + ExtensionRef filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') + && self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() + <= 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() + <= 1 + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + type: array + filters: + description: |- + Filters define the filters that are applied to requests that match + this rule. + + Wherever possible, implementations SHOULD implement filters in the order + they are specified. + + Implementations MAY choose to implement this ordering strictly, rejecting + any combination or order of filters that can not be supported. If implementations + choose a strict interpretation of filter ordering, they MUST clearly document + that behavior. + + To reject an invalid combination or order of filters, implementations SHOULD + consider the Route Rules with this configuration invalid. If all Route Rules + in a Route are invalid, the entire Route would be considered invalid. If only + a portion of Route Rules are invalid, implementations MUST set the + "PartiallyInvalid" condition for the Route. + + Conformance-levels at this level are defined based on the type of filter: + + - ALL core filters MUST be supported by all implementations. + - Implementers are encouraged to support extended filters. + - Implementation-specific custom filters have no API guarantees across + implementations. + + Specifying the same filter multiple times is not supported unless explicitly + indicated in the filter. + + All filters are expected to be compatible with each other except for the + URLRewrite and RequestRedirect filters, which may not be combined. If an + implementation can not support other combinations of filters, they must clearly + document that limitation. In cases where incompatible or unsupported + filters are specified and cause the `Accepted` condition to be set to status + `False`, implementations may use the `IncompatibleFilters` reason to specify + this configuration error. + + Support: Core + items: + description: |- + HTTPRouteFilter defines processing steps that must be completed during the + request or response lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway implementations. Some + examples include request or response modification, implementing + authentication strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type of the filter. + properties: + extensionRef: + description: |- + ExtensionRef is an optional, implementation-specific extension to the + "filter" behavior. For example, resource "myroutefilter" in group + "networking.example.net"). ExtensionRef MUST NOT be used for core and + extended filters. + + This filter can be used multiple times within the same rule. + + Support: Implementation-specific + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: |- + RequestHeaderModifier defines a schema for a filter that modifies request + headers. + + Support: Core + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: |+ + RequestMirror defines a schema for a filter that mirrors requests. + Requests are sent to the specified destination, but responses from + that destination are ignored. + + This filter can be used multiple times within the same rule. Note that + not all implementations will be able to support mirroring to multiple + backends. + + Support: Extended + + properties: + backendRef: + description: |- + BackendRef references a resource where mirrored requests are sent. + + Mirrored requests must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many endpoints are present + within this BackendRef. + + If the referent cannot be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure the "ResolvedRefs" + condition on the Route status is set to `status: False` and not configure + this backend in the underlying implementation. + + If there is a cross-namespace reference to an *existing* object + that is not allowed by a ReferenceGrant, the controller must ensure the + "ResolvedRefs" condition on the Route is set to `status: False`, + with the "RefNotPermitted" reason and not configure this backend in the + underlying implementation. + + In either error case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about the problem. + + Support: Extended for Kubernetes Service + + Support: Implementation-specific for any other resource + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - backendRef + type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' + requestRedirect: + description: |- + RequestRedirect defines a schema for a filter that responds to the + request with an HTTP redirection. + + Support: Core + properties: + hostname: + description: |- + Hostname is the hostname to be used in the value of the `Location` + header in the response. + When empty, the hostname in the `Host` header of the request is used. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the `Location` header. When + empty, the request path is used as-is. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + + If no port is specified, the redirect port MUST be derived using the + following rules: + + * If redirect scheme is not-empty, the redirect port MUST be the well-known + port associated with the redirect scheme. Specifically "http" to port 80 + and "https" to port 443. If the redirect scheme does not have a + well-known port, the listener port of the Gateway SHOULD be used. + * If redirect scheme is empty, the redirect port MUST be the Gateway + Listener port. + + Implementations SHOULD NOT add the port number in the 'Location' + header in the following cases: + + * A Location header that will use HTTP (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 80. + * A Location header that will use HTTPS (whether that is determined via + the Listener protocol or the Scheme field) _and_ use port 443. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: |- + Scheme is the scheme to be used in the value of the `Location` header in + the response. When empty, the scheme of the request is used. + + Scheme redirects can affect the port of the redirect, for more information, + refer to the documentation for the port field of this filter. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Extended + enum: + - http + - https + type: string + statusCode: + default: 302 + description: |- + StatusCode is the HTTP status code to be used in response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + + Support: Core + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: |- + ResponseHeaderModifier defines a schema for a filter that modifies response + headers. + + Support: Extended + properties: + add: + description: |- + Add adds the given header(s) (name, value) to the request + before the action. It appends to any existing values associated + with the header name. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + add: + - name: "my-header" + value: "bar,baz" + + Output: + GET /foo HTTP/1.1 + my-header: foo,bar,baz + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: |- + Remove the given header(s) from the HTTP request before the action. The + value of Remove is a list of HTTP header names. Note that the header + names are case-insensitive (see + https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + + Input: + GET /foo HTTP/1.1 + my-header1: foo + my-header2: bar + my-header3: baz + + Config: + remove: ["my-header1", "my-header3"] + + Output: + GET /foo HTTP/1.1 + my-header2: bar + items: + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + set: + description: |- + Set overwrites the request with the given header (name, value) + before the action. + + Input: + GET /foo HTTP/1.1 + my-header: foo + + Config: + set: + - name: "my-header" + value: "bar" + + Output: + GET /foo HTTP/1.1 + my-header: bar + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, the first entry with + an equivalent name MUST be considered for a match. Subsequent entries + with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + description: |- + Type identifies the type of filter to apply. As with other API fields, + types are classified into three conformance levels: + + - Core: Filter types and their corresponding configuration defined by + "Support: Core" in this package, e.g. "RequestHeaderModifier". All + implementations must support core filters. + + - Extended: Filter types and their corresponding configuration defined by + "Support: Extended" in this package, e.g. "RequestMirror". Implementers + are encouraged to support extended filters. + + - Implementation-specific: Filters that are defined and supported by + specific vendors. + In the future, filters showing convergence in behavior across multiple + implementations will be considered for inclusion in extended or core + conformance levels. Filter-specific configuration for such filters + is specified using the ExtensionRef field. `Type` should be set to + "ExtensionRef" for custom filters. + + Implementers are encouraged to define custom implementation types to + extend the core API with implementation-specific behavior. + + If a reference to a custom filter type cannot be resolved, the filter + MUST NOT be skipped. Instead, requests that would have been processed by + that filter MUST receive a HTTP error response. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestMirror + - RequestRedirect + - URLRewrite + - ExtensionRef + type: string + urlRewrite: + description: |- + URLRewrite defines a schema for a filter that modifies a request during forwarding. + + Support: Extended + properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines a path rewrite. + + Support: Extended + properties: + replaceFullPath: + description: |- + ReplaceFullPath specifies the value with which to replace the full path + of a request during a rewrite or redirect. + maxLength: 1024 + type: string + replacePrefixMatch: + description: |- + ReplacePrefixMatch specifies the value with which to replace the prefix + match of a request during a rewrite or redirect. For example, a request + to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch + of "/xyz" would be modified to "/xyz/bar". + + Note that this matches the behavior of the PathPrefix match type. This + matches full path elements. A path element refers to the list of labels + in the path split by the `/` separator. When specified, a trailing `/` is + ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all + match the prefix `/abc`, but the path `/abcd` would not. + + ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. + Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in + the implementation setting the Accepted Condition for the Route to `status: False`. + + Request Path | Prefix Match | Replace Prefix | Modified Path + maxLength: 1024 + type: string + type: + description: |- + Type defines the type of path modifier. Additional types may be + added in a future release of the API. + + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause a crash. + + Unknown values here must result in the implementation setting the + Accepted Condition for the Route to `status: False`, with a + Reason of `UnsupportedValue`. + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: replaceFullPath must be specified when + type is set to 'ReplaceFullPath' + rule: 'self.type == ''ReplaceFullPath'' ? has(self.replaceFullPath) + : true' + - message: type must be 'ReplaceFullPath' when replaceFullPath + is set + rule: 'has(self.replaceFullPath) ? self.type == + ''ReplaceFullPath'' : true' + - message: replacePrefixMatch must be specified when + type is set to 'ReplacePrefixMatch' + rule: 'self.type == ''ReplacePrefixMatch'' ? has(self.replacePrefixMatch) + : true' + - message: type must be 'ReplacePrefixMatch' when + replacePrefixMatch is set + rule: 'has(self.replacePrefixMatch) ? self.type + == ''ReplacePrefixMatch'' : true' + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: filter.requestHeaderModifier must be nil if the + filter.type is not RequestHeaderModifier + rule: '!(has(self.requestHeaderModifier) && self.type != + ''RequestHeaderModifier'')' + - message: filter.requestHeaderModifier must be specified + for RequestHeaderModifier filter.type + rule: '!(!has(self.requestHeaderModifier) && self.type == + ''RequestHeaderModifier'')' + - message: filter.responseHeaderModifier must be nil if the + filter.type is not ResponseHeaderModifier + rule: '!(has(self.responseHeaderModifier) && self.type != + ''ResponseHeaderModifier'')' + - message: filter.responseHeaderModifier must be specified + for ResponseHeaderModifier filter.type + rule: '!(!has(self.responseHeaderModifier) && self.type + == ''ResponseHeaderModifier'')' + - message: filter.requestMirror must be nil if the filter.type + is not RequestMirror + rule: '!(has(self.requestMirror) && self.type != ''RequestMirror'')' + - message: filter.requestMirror must be specified for RequestMirror + filter.type + rule: '!(!has(self.requestMirror) && self.type == ''RequestMirror'')' + - message: filter.requestRedirect must be nil if the filter.type + is not RequestRedirect + rule: '!(has(self.requestRedirect) && self.type != ''RequestRedirect'')' + - message: filter.requestRedirect must be specified for RequestRedirect + filter.type + rule: '!(!has(self.requestRedirect) && self.type == ''RequestRedirect'')' + - message: filter.urlRewrite must be nil if the filter.type + is not URLRewrite + rule: '!(has(self.urlRewrite) && self.type != ''URLRewrite'')' + - message: filter.urlRewrite must be specified for URLRewrite + filter.type + rule: '!(!has(self.urlRewrite) && self.type == ''URLRewrite'')' + - message: filter.extensionRef must be nil if the filter.type + is not ExtensionRef + rule: '!(has(self.extensionRef) && self.type != ''ExtensionRef'')' + - message: filter.extensionRef must be specified for ExtensionRef + filter.type + rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: May specify either httpRouteFilterRequestRedirect + or httpRouteFilterRequestRewrite, but not both + rule: '!(self.exists(f, f.type == ''RequestRedirect'') && + self.exists(f, f.type == ''URLRewrite''))' + - message: RequestHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'RequestHeaderModifier').size() + <= 1 + - message: ResponseHeaderModifier filter cannot be repeated + rule: self.filter(f, f.type == 'ResponseHeaderModifier').size() + <= 1 + - message: RequestRedirect filter cannot be repeated + rule: self.filter(f, f.type == 'RequestRedirect').size() <= + 1 + - message: URLRewrite filter cannot be repeated + rule: self.filter(f, f.type == 'URLRewrite').size() <= 1 + matches: + default: + - path: + type: PathPrefix + value: / + description: |- + Matches define conditions used for matching the rule against incoming + HTTP requests. Each match is independent, i.e. this rule will be matched + if **any** one of the matches is satisfied. + + For example, take the following matches configuration: + + ``` + matches: + - path: + value: "/foo" + headers: + - name: "version" + value: "v2" + - path: + value: "/v2/foo" + ``` + + For a request to match against this rule, a request must satisfy + EITHER of the two conditions: + + - path prefixed with `/foo` AND contains the header `version: v2` + - path prefix of `/v2/foo` + + See the documentation for HTTPRouteMatch on how to specify multiple + match conditions that should be ANDed together. + + If no matches are specified, the default is a prefix + path match on "/", which has the effect of matching every + HTTP request. + + Proxy or Load Balancer routing configuration generated from HTTPRoutes + MUST prioritize matches based on the following criteria, continuing on + ties. Across all rules specified on applicable Routes, precedence must be + given to the match having: + + * "Exact" path match. + * "Prefix" path match with largest number of characters. + * Method match. + * Largest number of header matches. + * Largest number of query param matches. + + Note: The precedence of RegularExpression path matches are implementation-specific. + + If ties still exist across multiple Routes, matching precedence MUST be + determined in order of the following criteria, continuing on ties: + + * The oldest Route based on creation timestamp. + * The Route appearing first in alphabetical order by + "{namespace}/{name}". + + If ties still exist within an HTTPRoute, matching precedence MUST be granted + to the FIRST matching rule (in list order) with a match meeting the above + criteria. + + When no rules matching a request have been successfully attached to the + parent a request is coming from, a HTTP 404 status code MUST be returned. + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given\naction. Multiple match types + are ANDed together, i.e. the match will\nevaluate to true + only if all conditions are satisfied.\n\nFor example, the + match below will match a HTTP request only if its path\nstarts + with `/foo` AND it contains the `version: v1` header:\n\n```\nmatch:\n\n\tpath:\n\t + \ value: \"/foo\"\n\theaders:\n\t- name: \"version\"\n\t + \ value \"v1\"\n\n```" + properties: + headers: + description: |- + Headers specifies HTTP request header matchers. Multiple match values are + ANDed together, meaning, a request must match all the specified headers + to select the route. + items: + description: |- + HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name matching MUST be + case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + + If multiple entries specify equivalent header names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be ignored. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered + equivalent. + + When a header is repeated in an HTTP request, it is + implementation-specific behavior as to how this is represented. + Generally, proxies should follow the guidance from the RFC: + https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding + processing a repeated header, with special handling for "Set-Cookie". + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the header. + + Support: Core (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression HeaderMatchType has implementation-specific + conformance, implementations can support POSIX, PCRE or any other dialects + of regular expressions. Please read the implementation's documentation to + determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: |- + Method specifies HTTP method matcher. + When specified, this route will be matched only if the request has the + specified method. + + Support: Extended + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: |- + Path specifies a HTTP request path matcher. If this field is not + specified, a default prefix match on the "/" path is provided. + properties: + type: + default: PathPrefix + description: |- + Type specifies how to match against the path Value. + + Support: Core (Exact, PathPrefix) + + Support: Implementation-specific (RegularExpression) + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + x-kubernetes-validations: + - message: value must be an absolute path and start with + '/' when type one of ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.startsWith(''/'') + : true' + - message: must not contain '//' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''//'') + : true' + - message: must not contain '/./' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/./'') + : true' + - message: must not contain '/../' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''/../'') + : true' + - message: must not contain '%2f' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2f'') + : true' + - message: must not contain '%2F' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''%2F'') + : true' + - message: must not contain '#' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.contains(''#'') + : true' + - message: must not end with '/..' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/..'') + : true' + - message: must not end with '/.' when type one of ['Exact', + 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? !self.value.endsWith(''/.'') + : true' + - message: type must be one of ['Exact', 'PathPrefix', + 'RegularExpression'] + rule: self.type in ['Exact','PathPrefix'] || self.type + == 'RegularExpression' + - message: must only contain valid characters (matching + ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$) + for types ['Exact', 'PathPrefix'] + rule: '(self.type in [''Exact'',''PathPrefix'']) ? self.value.matches(r"""^(?:[-A-Za-z0-9/._~!$&''()*+,;=:@]|[%][0-9a-fA-F]{2})+$""") + : true' + queryParams: + description: |- + QueryParams specifies HTTP query parameter matchers. Multiple match + values are ANDed together, meaning, a request must match all the + specified query parameters to select the route. + + Support: Extended + items: + description: |- + HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP + query parameters. + properties: + name: + description: |- + Name is the name of the HTTP query param to be matched. This must be an + exact string match. (See + https://tools.ietf.org/html/rfc7230#section-2.7.3). + + If multiple entries specify equivalent query param names, only the first + entry with an equivalent name MUST be considered for a match. Subsequent + entries with an equivalent query param name MUST be ignored. + + If a query param is repeated in an HTTP request, the behavior is + purposely left undefined, since different data planes have different + capabilities. However, it is *recommended* that implementations should + match against the first value of the param if the data plane supports it, + as this behavior is expected in other load balancing contexts outside of + the Gateway API. + + Users SHOULD NOT route traffic based on repeated query params to guard + themselves against potential differences in the implementations. + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: |- + Type specifies how to match against the value of the query parameter. + + Support: Extended (Exact) + + Support: Implementation-specific (RegularExpression) + + Since RegularExpression QueryParamMatchType has Implementation-specific + conformance, implementations can support POSIX, PCRE or any other + dialects of regular expressions. Please read the implementation's + documentation to determine the supported dialect. + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 64 + type: array + name: + description: | + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + retry: + description: |+ + Retry defines the configuration for when to retry an HTTP request. + + Support: Extended + + properties: + attempts: + description: |- + Attempts specifies the maxmimum number of times an individual request + from the gateway to a backend should be retried. + + If the maximum number of retries has been attempted without a successful + response from the backend, the Gateway MUST return an error. + + When this field is unspecified, the number of times to attempt to retry + a backend request is implementation-specific. + + Support: Extended + type: integer + backoff: + description: |- + Backoff specifies the minimum duration a Gateway should wait between + retry attempts and is represented in Gateway API Duration formatting. + + For example, setting the `rules[].retry.backoff` field to the value + `100ms` will cause a backend request to first be retried approximately + 100 milliseconds after timing out or receiving a response code configured + to be retryable. + + An implementation MAY use an exponential or alternative backoff strategy + for subsequent retry attempts, MAY cap the maximum backoff duration to + some amount greater than the specified minimum, and MAY add arbitrary + jitter to stagger requests, as long as unsuccessful backend requests are + not retried before the configured minimum duration. + + If a Request timeout (`rules[].timeouts.request`) is configured on the + route, the entire duration of the initial request and any retry attempts + MUST not exceed the Request timeout duration. If any retry attempts are + still in progress when the Request timeout duration has been reached, + these SHOULD be canceled if possible and the Gateway MUST immediately + return a timeout error. + + If a BackendRequest timeout (`rules[].timeouts.backendRequest`) is + configured on the route, any retry attempts which reach the configured + BackendRequest timeout duration without a response SHOULD be canceled if + possible and the Gateway should wait for at least the specified backoff + duration before attempting to retry the backend request again. + + If a BackendRequest timeout is _not_ configured on the route, retry + attempts MAY time out after an implementation default duration, or MAY + remain pending until a configured Request timeout or implementation + default duration for total request time is reached. + + When this field is unspecified, the time to wait between retry attempts + is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + codes: + description: |- + Codes defines the HTTP response status codes for which a backend request + should be retried. + + Support: Extended + items: + description: |- + HTTPRouteRetryStatusCode defines an HTTP response status code for + which a backend request should be retried. + + Implementations MUST support the following status codes as retryable: + + * 500 + * 502 + * 503 + * 504 + + Implementations MAY support specifying additional discrete values in the + 500-599 range. + + Implementations MAY support specifying discrete values in the 400-499 range, + which are often inadvisable to retry. + + <gateway:experimental> + maximum: 599 + minimum: 400 + type: integer + type: array + type: object + sessionPersistence: + description: |+ + SessionPersistence defines and configures session persistence + for the route rule. + + Support: Extended + + properties: + absoluteTimeout: + description: |- + AbsoluteTimeout defines the absolute timeout of the persistent + session. Once the AbsoluteTimeout duration has elapsed, the + session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + cookieConfig: + description: |- + CookieConfig provides configuration settings that are specific + to cookie-based session persistence. + + Support: Core + properties: + lifetimeType: + default: Session + description: |- + LifetimeType specifies whether the cookie has a permanent or + session-based lifetime. A permanent cookie persists until its + specified expiry time, defined by the Expires or Max-Age cookie + attributes, while a session cookie is deleted when the current + session ends. + + When set to "Permanent", AbsoluteTimeout indicates the + cookie's lifetime via the Expires or Max-Age cookie attributes + and is required. + + When set to "Session", AbsoluteTimeout indicates the + absolute lifetime of the cookie tracked by the gateway and + is optional. + + Support: Core for "Session" type + + Support: Extended for "Permanent" type + enum: + - Permanent + - Session + type: string + type: object + idleTimeout: + description: |- + IdleTimeout defines the idle timeout of the persistent session. + Once the session has been idle for more than the specified + IdleTimeout duration, the session becomes invalid. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + sessionName: + description: |- + SessionName defines the name of the persistent session token + which may be reflected in the cookie or the header. Users + should avoid reusing session names to prevent unintended + consequences, such as rejection or unpredictable behavior. + + Support: Implementation-specific + maxLength: 128 + type: string + type: + default: Cookie + description: |- + Type defines the type of session persistence such as through + the use a header or cookie. Defaults to cookie based session + persistence. + + Support: Core for "Cookie" type + + Support: Extended for "Header" type + enum: + - Cookie + - Header + type: string + type: object + x-kubernetes-validations: + - message: AbsoluteTimeout must be specified when cookie lifetimeType + is Permanent + rule: '!has(self.cookieConfig) || !has(self.cookieConfig.lifetimeType) + || self.cookieConfig.lifetimeType != ''Permanent'' || has(self.absoluteTimeout)' + timeouts: + description: |- + Timeouts defines the timeouts that can be configured for an HTTP request. + + Support: Extended + properties: + backendRequest: + description: |- + BackendRequest specifies a timeout for an individual request from the gateway + to a backend. This covers the time from when the request first starts being + sent from the gateway to when the full response has been received from the backend. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + An entire client HTTP transaction with a gateway, covered by the Request timeout, + may result in more than one call from the gateway to the destination backend, + for example, if automatic retries are supported. + + The value of BackendRequest must be a Gateway API Duration string as defined by + GEP-2257. When this field is unspecified, its behavior is implementation-specific; + when specified, the value of BackendRequest must be no more than the value of the + Request timeout (since the Request timeout encompasses the BackendRequest timeout). + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + request: + description: |- + Request specifies the maximum duration for a gateway to respond to an HTTP request. + If the gateway has not been able to respond before this deadline is met, the gateway + MUST return a timeout error. + + For example, setting the `rules.timeouts.request` field to the value `10s` in an + `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds + to complete. + + Setting a timeout to the zero duration (e.g. "0s") SHOULD disable the timeout + completely. Implementations that cannot completely disable the timeout MUST + instead interpret the zero duration as the longest possible value to which + the timeout can be set. + + This timeout is intended to cover as close to the whole request-response transaction + as possible although an implementation MAY choose to start the timeout after the entire + request stream has been received instead of immediately after the transaction is + initiated by the client. + + The value of Request is a Gateway API Duration string as defined by GEP-2257. When this + field is unspecified, request timeout behavior is implementation-specific. + + Support: Extended + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + x-kubernetes-validations: + - message: backendRequest timeout cannot be longer than request + timeout + rule: '!(has(self.request) && has(self.backendRequest) && + duration(self.request) != duration(''0s'') && duration(self.backendRequest) + > duration(self.request))' + type: object + x-kubernetes-validations: + - message: RequestRedirect filter must not be used together with + backendRefs + rule: '(has(self.backendRefs) && size(self.backendRefs) > 0) ? + (!has(self.filters) || self.filters.all(f, !has(f.requestRedirect))): + true' + - message: When using RequestRedirect filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + ? ((size(self.matches) != 1 || !has(self.matches[0].path) || + self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: When using URLRewrite filter with path.replacePrefixMatch, + exactly one PathPrefix match must be specified + rule: '(has(self.filters) && self.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + - message: Within backendRefs, when using RequestRedirect filter + with path.replacePrefixMatch, exactly one PathPrefix match must + be specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.requestRedirect) + && has(f.requestRedirect.path) && f.requestRedirect.path.type + == ''ReplacePrefixMatch'' && has(f.requestRedirect.path.replacePrefixMatch))) + )) ? ((size(self.matches) != 1 || !has(self.matches[0].path) + || self.matches[0].path.type != ''PathPrefix'') ? false : true) + : true' + - message: Within backendRefs, When using URLRewrite filter with + path.replacePrefixMatch, exactly one PathPrefix match must be + specified + rule: '(has(self.backendRefs) && self.backendRefs.exists_one(b, + (has(b.filters) && b.filters.exists_one(f, has(f.urlRewrite) + && has(f.urlRewrite.path) && f.urlRewrite.path.type == ''ReplacePrefixMatch'' + && has(f.urlRewrite.path.replacePrefixMatch))) )) ? ((size(self.matches) + != 1 || !has(self.matches[0].path) || self.matches[0].path.type + != ''PathPrefix'') ? false : true) : true' + maxItems: 16 + type: array + x-kubernetes-validations: + - message: While 16 rules and 64 matches per rule are allowed, the + total number of matches across all rules in a route must be less + than 128 + rule: '(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() + > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() + : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() + > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() + : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() + > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() + : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() + > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() + : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() + > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() + : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: referencegrants.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: ReferenceGrant + listKind: ReferenceGrantList + plural: referencegrants + shortNames: + - refgrant + singular: referencegrant + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: |- + ReferenceGrant identifies kinds of resources in other namespaces that are + trusted to reference the specified kinds of resources in the same namespace + as the policy. + + Each ReferenceGrant can be used to represent a unique trust relationship. + Additional Reference Grants can be used to add to the set of trusted + sources of inbound references for the namespace they are defined within. + + All cross-namespace references in Gateway API (with the exception of cross-namespace + Gateway-route attachment) require a ReferenceGrant. + + ReferenceGrant is a form of runtime verification allowing users to assert + which cross-namespace object references are permitted. Implementations that + support ReferenceGrant MUST NOT permit cross-namespace references which have + no grant, and MUST respond to the removal of a grant by revoking the access + that the grant allowed. + 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: + description: Spec defines the desired state of ReferenceGrant. + properties: + from: + description: |- + From describes the trusted namespaces and kinds that can reference the + resources described in "To". Each entry in this list MUST be considered + to be an additional place that references can be valid from, or to put + this another way, entries MUST be combined using OR. + + Support: Core + items: + description: ReferenceGrantFrom describes trusted namespaces and + kinds. + properties: + group: + description: |- + Group is the group of the referent. + When empty, the Kubernetes core API group is inferred. + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: |- + Kind is the kind of the referent. Although implementations may support + additional resources, the following types are part of the "Core" + support level for this field. + + When used to permit a SecretObjectReference: + + * Gateway + + When used to permit a BackendObjectReference: + + * GRPCRoute + * HTTPRoute + * TCPRoute + * TLSRoute + * UDPRoute + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + namespace: + description: |- + Namespace is the namespace of the referent. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - namespace + type: object + maxItems: 16 + minItems: 1 + type: array + to: + description: |- + To describes the resources that may be referenced by the resources + described in "From". Each entry in this list MUST be considered to be an + additional place that references can be valid to, or to put this another + way, entries MUST be combined using OR. + + Support: Core + items: + description: |- + ReferenceGrantTo describes what Kinds are allowed as targets of the + references. + properties: + group: + description: |- + Group is the group of the referent. + When empty, the Kubernetes core API group is inferred. + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: |- + Kind is the kind of the referent. Although implementations may support + additional resources, the following types are part of the "Core" + support level for this field: + + * Secret when used to permit a SecretObjectReference + * Service when used to permit a BackendObjectReference + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. When unspecified, this policy + refers to all resources of the specified Group and Kind in the local + namespace. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + type: object + maxItems: 16 + minItems: 1 + type: array + required: + - from + - to + type: object + type: object + served: true + storage: true + subresources: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: tcproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: TCPRoute + listKind: TCPRouteList + plural: tcproutes + singular: tcproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + TCPRoute provides a way to route TCP requests. When combined with a Gateway + listener, it can be used to forward connections on the port specified by the + listener to a set of backends specified by the TCPRoute. + 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: + description: Spec defines the desired state of TCPRoute. + properties: + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + description: |+ + Rules are a list of TCP matchers and actions. + + items: + description: TCPRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. If unspecified or invalid (refers to a non-existent resource or a + Service with no endpoints), the underlying implementation MUST actively + reject connection attempts to this backend. Connection rejections must + respect weight; if an invalid backend is requested to have 80% of + connections, then 80% of connections must be rejected instead. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Extended + items: + description: |- + BackendRef defines how a Route should forward a request to a Kubernetes + resource. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + <gateway:experimental:description> + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + </gateway:experimental:description> + + Note that when the BackendTLSPolicy object is enabled by the implementation, + there are some extra rules about validity to consider here. See the fields + where this struct is used for more information about the exact behavior. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + minItems: 1 + type: array + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-validations: + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + required: + - rules + type: object + status: + description: Status defines the current state of TCPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: tlsroutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: TLSRoute + listKind: TLSRouteList + plural: tlsroutes + singular: tlsroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + The TLSRoute resource is similar to TCPRoute, but can be configured + to match against TLS-specific metadata. This allows more flexibility + in matching streams for a given TLS listener. + + If you need to forward traffic to a single target for a TLS listener, you + could choose to use a TCPRoute with a TLS listener. + 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: + description: Spec defines the desired state of TLSRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of SNI names that should match against the + SNI attribute of TLS ClientHello message in TLS handshake. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed in SNI names per RFC 6066. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and TLSRoute, there + must be at least one intersecting hostname for the TLSRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches TLSRoutes + that have either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches TLSRoutes + that have either not specified any hostnames or have specified at least + one hostname that matches the Listener hostname. For example, + `test.example.com` and `*.example.com` would both match. On the other + hand, `example.com` and `test.example.net` would not match. + + If both the Listener and TLSRoute have specified hostnames, any + TLSRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + TLSRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and TLSRoute have specified hostnames, and none + match with the criteria above, then the TLSRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + description: |+ + Rules are a list of TLS matchers and actions. + + items: + description: TLSRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. If unspecified or invalid (refers to a non-existent resource or + a Service with no endpoints), the rule performs no forwarding; if no + filters are specified that would result in a response being sent, the + underlying implementation must actively reject request attempts to this + backend, by rejecting the connection or returning a 500 status code. + Request rejections must respect weight; if an invalid backend is + requested to have 80% of requests, then 80% of requests must be rejected + instead. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Extended + items: + description: |- + BackendRef defines how a Route should forward a request to a Kubernetes + resource. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + <gateway:experimental:description> + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + </gateway:experimental:description> + + Note that when the BackendTLSPolicy object is enabled by the implementation, + there are some extra rules about validity to consider here. See the fields + where this struct is used for more information about the exact behavior. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + minItems: 1 + type: array + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-validations: + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + required: + - rules + type: object + status: + description: Status defines the current state of TLSRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 + gateway.networking.k8s.io/channel: experimental + creationTimestamp: null + name: udproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: UDPRoute + listKind: UDPRouteList + plural: udproutes + singular: udproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + UDPRoute provides a way to route UDP traffic. When combined with a Gateway + listener, it can be used to forward traffic on the port specified by the + listener to a set of backends specified by the UDPRoute. + 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: + description: Spec defines the desired state of UDPRoute. + properties: + parentRefs: + description: |+ + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + + + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + description: |+ + Rules are a list of UDP matchers and actions. + + items: + description: UDPRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. If unspecified or invalid (refers to a non-existent resource or a + Service with no endpoints), the underlying implementation MUST actively + reject connection attempts to this backend. Packet drops must + respect weight; if an invalid backend is requested to have 80% of + the packets, then 80% of packets must be dropped instead. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Extended + items: + description: |- + BackendRef defines how a Route should forward a request to a Kubernetes + resource. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + <gateway:experimental:description> + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + If a Service appProtocol isn't specified, an implementation MAY infer the + backend protocol through its own means. Implementations MAY infer the + protocol from the Route type referring to the backend Service. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + </gateway:experimental:description> + + Note that when the BackendTLSPolicy object is enabled by the implementation, + there are some extra rules about validity to consider here. See the fields + where this struct is used for more information about the exact behavior. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + minItems: 1 + type: array + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-validations: + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + required: + - rules + type: object + status: + description: Status defines the current state of UDPRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a non-existent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/packages/system/kamaji/Makefile b/packages/system/kamaji/Makefile index 0956527d..aa864c1a 100644 --- a/packages/system/kamaji/Makefile +++ b/packages/system/kamaji/Makefile @@ -14,6 +14,8 @@ update: image: docker buildx build images/kamaji \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/kamaji:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/kamaji:latest \ --cache-to type=inline \ diff --git a/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_datastores.yaml b/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_datastores.yaml index f3071767..aeb221e2 100644 --- a/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_datastores.yaml +++ b/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_datastores.yaml @@ -120,6 +120,9 @@ spec: - PostgreSQL - NATS type: string + x-kubernetes-validations: + - message: Datastore driver is immutable + rule: self == oldSelf endpoints: description: |- List of the endpoints to connect to the shared datastore. @@ -263,6 +266,21 @@ spec: - driver - endpoints type: object + x-kubernetes-validations: + - message: certificateAuthority privateKey must have secretReference or content when driver is etcd + rule: '(self.driver == "etcd") ? (self.tlsConfig != null && (has(self.tlsConfig.certificateAuthority.privateKey.secretReference) || has(self.tlsConfig.certificateAuthority.privateKey.content))) : true' + - message: clientCertificate must have secretReference or content when driver is etcd + rule: '(self.driver == "etcd") ? (self.tlsConfig != null && (has(self.tlsConfig.clientCertificate.certificate.secretReference) || has(self.tlsConfig.clientCertificate.certificate.content))) : true' + - message: clientCertificate privateKey must have secretReference or content when driver is etcd + rule: '(self.driver == "etcd") ? (self.tlsConfig != null && (has(self.tlsConfig.clientCertificate.privateKey.secretReference) || has(self.tlsConfig.clientCertificate.privateKey.content))) : true' + - message: When driver is not etcd and tlsConfig exists, clientCertificate must be null or contain valid content + rule: '(self.driver != "etcd" && has(self.tlsConfig) && has(self.tlsConfig.clientCertificate)) ? (((has(self.tlsConfig.clientCertificate.certificate.secretReference) || has(self.tlsConfig.clientCertificate.certificate.content)))) : true' + - message: When driver is not etcd and basicAuth exists, username must have secretReference or content + rule: '(self.driver != "etcd" && has(self.basicAuth)) ? ((has(self.basicAuth.username.secretReference) || has(self.basicAuth.username.content))) : true' + - message: When driver is not etcd and basicAuth exists, password must have secretReference or content + rule: '(self.driver != "etcd" && has(self.basicAuth)) ? ((has(self.basicAuth.password.secretReference) || has(self.basicAuth.password.content))) : true' + - message: When driver is not etcd, either tlsConfig or basicAuth must be provided + rule: '(self.driver != "etcd") ? (has(self.tlsConfig) || has(self.basicAuth)) : true' status: description: DataStoreStatus defines the observed state of DataStore. properties: diff --git a/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_tenantcontrolplanes.yaml b/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_tenantcontrolplanes.yaml index bb26cdcc..b3d3b668 100644 --- a/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_tenantcontrolplanes.yaml +++ b/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_tenantcontrolplanes.yaml @@ -427,7 +427,7 @@ spec: Values defined by an Env with a duplicate key will take precedence. Cannot be updated. items: - description: EnvFromSource represents the source of a set of ConfigMaps + description: EnvFromSource represents the source of a set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from @@ -447,7 +447,7 @@ spec: type: object x-kubernetes-map-type: atomic prefix: - description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + description: Optional text to prepend to the name of each environment variable. Must be a C_IDENTIFIER. type: string secretRef: description: The Secret to select from @@ -696,6 +696,12 @@ spec: - port type: object type: object + stopSignal: + description: |- + StopSignal defines which signal will be sent to a container when it is being stopped. + If not specified, the default is defined by the container runtime in use. + StopSignal can only be set for Pods with a non-empty .spec.os.name + type: string type: object livenessProbe: description: |- @@ -1792,7 +1798,7 @@ spec: Values defined by an Env with a duplicate key will take precedence. Cannot be updated. items: - description: EnvFromSource represents the source of a set of ConfigMaps + description: EnvFromSource represents the source of a set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from @@ -1812,7 +1818,7 @@ spec: type: object x-kubernetes-map-type: atomic prefix: - description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + description: Optional text to prepend to the name of each environment variable. Must be a C_IDENTIFIER. type: string secretRef: description: The Secret to select from @@ -2061,6 +2067,12 @@ spec: - port type: object type: object + stopSignal: + description: |- + StopSignal defines which signal will be sent to a container when it is being stopped. + If not specified, the default is defined by the container runtime in use. + StopSignal can only be set for Pods with a non-empty .spec.os.name + type: string type: object livenessProbe: description: |- @@ -4087,7 +4099,7 @@ spec: The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. The volume will be mounted read-only (ro) and non-executable files (noexec). - Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. properties: pullPolicy: @@ -5173,7 +5185,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5188,7 +5199,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5349,7 +5359,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5364,7 +5373,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5518,7 +5526,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5533,7 +5540,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5694,7 +5700,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -5709,7 +5714,6 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -6339,7 +6343,6 @@ spec: - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. If this value is nil, the behavior is equivalent to the Honor policy. - This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string nodeTaintsPolicy: description: |- @@ -6350,7 +6353,6 @@ spec: - Ignore: node taints are ignored. All nodes are included. If this value is nil, the behavior is equivalent to the Ignore policy. - This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string topologyKey: description: |- @@ -7071,7 +7073,7 @@ spec: description: KubernetesDeploymentStatus defines the status for the Tenant Control Plane Deployment in the management cluster. properties: availableReplicas: - description: Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. + description: Total number of available non-terminating pods (ready for at least minReadySeconds) targeted by this deployment. format: int32 type: integer collisionCount: @@ -7129,16 +7131,24 @@ spec: format: int64 type: integer readyReplicas: - description: readyReplicas is the number of pods targeted by this Deployment with a Ready Condition. + description: Total number of non-terminating pods targeted by this Deployment with a Ready Condition. format: int32 type: integer replicas: - description: Total number of non-terminated pods targeted by this deployment (their labels match the selector). + description: Total number of non-terminating pods targeted by this deployment (their labels match the selector). format: int32 type: integer selector: description: Selector is the label selector used to group the Tenant Control Plane Pods used by the scale subresource. type: string + terminatingReplicas: + description: |- + Total number of terminating pods targeted by this deployment. Terminating pods have a non-null + .metadata.deletionTimestamp and have not yet reached the Failed or Succeeded .status.phase. + + This is an alpha field. Enable DeploymentReplicaSetTerminatingReplicas to be able to use this field. + format: int32 + type: integer unavailableReplicas: description: |- Total number of unavailable pods targeted by this deployment. This is the total number of @@ -7147,7 +7157,7 @@ spec: format: int32 type: integer updatedReplicas: - description: Total number of non-terminated pods targeted by this deployment that have the desired template spec. + description: Total number of non-terminating pods targeted by this deployment that have the desired template spec. format: int32 type: integer required: @@ -7379,6 +7389,7 @@ spec: - Migrating - Ready - NotReady + - Sleeping type: string version: description: Version is the running Kubernetes version of the Tenant Control Plane. diff --git a/packages/system/kamaji/charts/kamaji/templates/controller.yaml b/packages/system/kamaji/charts/kamaji/templates/controller.yaml index 38d635dd..63178382 100644 --- a/packages/system/kamaji/charts/kamaji/templates/controller.yaml +++ b/packages/system/kamaji/charts/kamaji/templates/controller.yaml @@ -19,10 +19,6 @@ spec: labels: {{- include "kamaji.selectorLabels" . | nindent 8 }} spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} serviceAccountName: {{ include "kamaji.serviceAccountName" . }} diff --git a/packages/system/kamaji/charts/kamaji/templates/rbac.yaml b/packages/system/kamaji/charts/kamaji/templates/rbac.yaml index aa4301db..43a1866f 100644 --- a/packages/system/kamaji/charts/kamaji/templates/rbac.yaml +++ b/packages/system/kamaji/charts/kamaji/templates/rbac.yaml @@ -9,6 +9,10 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} namespace: {{ .Release.Namespace }} +{{- with .Values.imagePullSecrets }} +imagePullSecrets: + {{- toYaml . | nindent 2 }} +{{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role diff --git a/packages/system/kamaji/images/kamaji/Dockerfile b/packages/system/kamaji/images/kamaji/Dockerfile index 58007bd3..e7bd44be 100644 --- a/packages/system/kamaji/images/kamaji/Dockerfile +++ b/packages/system/kamaji/images/kamaji/Dockerfile @@ -1,8 +1,9 @@ # Build the manager binary -FROM golang:1.23 as builder +FROM golang:1.24 as builder -ARG VERSION=edge-25.3.2 -ARG TARGETOS TARGETARCH +ARG VERSION=edge-25.4.1 +ARG TARGETOS +ARG TARGETARCH WORKDIR /workspace @@ -11,7 +12,7 @@ RUN curl -sSL https://github.com/clastix/kamaji/archive/refs/tags/${VERSION}.tar COPY patches /patches RUN git apply /patches/*.diff -RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build \ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build \ -ldflags "-X github.com/clastix/kamaji/internal.GitRepo=$GIT_REPO -X github.com/clastix/kamaji/internal.GitTag=$GIT_LAST_TAG -X github.com/clastix/kamaji/internal.GitCommit=$GIT_HEAD_COMMIT -X github.com/clastix/kamaji/internal.GitDirty=$GIT_MODIFIED -X github.com/clastix/kamaji/internal.BuildTime=$BUILD_DATE" \ -a -o kamaji main.go diff --git a/packages/system/kamaji/images/kamaji/patches/hardcode-port.diff b/packages/system/kamaji/images/kamaji/patches/hardcode-port.diff deleted file mode 100644 index 5e80d417..00000000 --- a/packages/system/kamaji/images/kamaji/patches/hardcode-port.diff +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/internal/resources/kubeadm_config.go b/internal/resources/kubeadm_config.go -index ae4cfc0..ec7a7da 100644 ---- a/internal/resources/kubeadm_config.go -+++ b/internal/resources/kubeadm_config.go -@@ -96,7 +96,7 @@ func (r *KubeadmConfigResource) mutate(ctx context.Context, tenantControlPlane * - TenantControlPlanePort: port, - TenantControlPlaneName: tenantControlPlane.GetName(), - TenantControlPlaneNamespace: tenantControlPlane.GetNamespace(), -- TenantControlPlaneEndpoint: r.getControlPlaneEndpoint(tenantControlPlane.Spec.ControlPlane.Ingress, address, port), -+ TenantControlPlaneEndpoint: r.getControlPlaneEndpoint(tenantControlPlane.Spec.ControlPlane.Ingress, address, 443), - TenantControlPlaneCertSANs: tenantControlPlane.Spec.NetworkProfile.CertSANs, - TenantControlPlaneClusterDomain: tenantControlPlane.Spec.NetworkProfile.ClusterDomain, - TenantControlPlanePodCIDR: tenantControlPlane.Spec.NetworkProfile.PodCIDR, diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 7abe514e..828903ab 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.30.2@sha256:e04f68e4cc5b023ed39ce2242b32aee51f97235371602239d0c4a9cea97c8d0d + tag: v0.31.0-rc.3@sha256:5f828637ebd1717a5c2b828352fff7fc14c218c7bbfc2cb2ce55737f9b5bf500 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: diff --git a/packages/system/keycloak/templates/ingress.yaml b/packages/system/keycloak/templates/ingress.yaml index 7618a9f5..30120619 100644 --- a/packages/system/keycloak/templates/ingress.yaml +++ b/packages/system/keycloak/templates/ingress.yaml @@ -1,9 +1,7 @@ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} {{- $host := index $cozyConfig.data "root-host" }} {{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $rootns := lookup "v1" "Namespace" "" "tenant-root" }} -{{- $ingress := index $rootns.metadata.annotations "namespace.cozystack.io/ingress" }} +{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} apiVersion: networking.k8s.io/v1 kind: Ingress @@ -12,13 +10,13 @@ metadata: {{- with .Values.ingress.annotations }} annotations: {{- if ne $issuerType "cloudflare" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + acme.cert-manager.io/http01-ingress-class: {{ $exposeIngress }} {{- end }} cert-manager.io/cluster-issuer: letsencrypt-prod {{- toYaml . | nindent 4 }} {{- end }} spec: - ingressClassName: {{ $ingress }} + ingressClassName: {{ $exposeIngress }} tls: - hosts: - keycloak.{{ $host }} diff --git a/packages/system/kubeovn-webhook/Makefile b/packages/system/kubeovn-webhook/Makefile index 2605ca5e..76bf5f5a 100644 --- a/packages/system/kubeovn-webhook/Makefile +++ b/packages/system/kubeovn-webhook/Makefile @@ -7,6 +7,8 @@ include ../../../scripts/package.mk image: docker buildx build images/kubeovn-webhook \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/kubeovn-webhook:$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/kubeovn-webhook:latest \ --cache-to type=inline \ diff --git a/packages/system/kubeovn-webhook/images/kubeovn-webhook/Dockerfile b/packages/system/kubeovn-webhook/images/kubeovn-webhook/Dockerfile index 337e72e4..73d5e99b 100644 --- a/packages/system/kubeovn-webhook/images/kubeovn-webhook/Dockerfile +++ b/packages/system/kubeovn-webhook/images/kubeovn-webhook/Dockerfile @@ -1,11 +1,14 @@ -FROM golang:1.23 as builder +FROM golang:1.23 AS builder + +ARG TARGETOS +ARG TARGETARCH WORKDIR /app COPY go.mod go.sum ./ -RUN go mod download +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download COPY . . -RUN CGO_ENABLED=0 GOOS=linux go build -o webhook . +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o webhook . FROM alpine:3.21.3 WORKDIR /app diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index db3c347e..b9df2b38 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.30.2@sha256:fa14fa7a0ffa628eb079ddcf6ce41d75b43de92e50f489422f8fb15c4dab2dbf +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.31.0-rc.3@sha256:f3acc1c6dd87cebd76be5afe1789c19780cb24f9518c8bdafa46f823ae4ba46e diff --git a/packages/system/kubeovn/Makefile b/packages/system/kubeovn/Makefile index 559dd118..62f0afae 100644 --- a/packages/system/kubeovn/Makefile +++ b/packages/system/kubeovn/Makefile @@ -1,4 +1,4 @@ -KUBEOVN_TAG = v1.13.8 +KUBEOVN_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/kube-ovn/Chart.yaml) export NAME=kubeovn export NAMESPACE=cozy-$(NAME) @@ -13,10 +13,14 @@ update: tar xzvf - --strip 1 kube-ovn-$${tag#*v}/charts patch --no-backup-if-mismatch -p4 < patches/cozyconfig.diff patch --no-backup-if-mismatch -p4 < patches/mtu.diff + version=$$(awk '$$1 == "version:" {print $$2}' charts/kube-ovn/Chart.yaml) && \ + sed -i "s/ARG VERSION=.*/ARG VERSION=$${version}/" images/kubeovn/Dockerfile image: docker buildx build images/kubeovn \ --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ --tag $(REGISTRY)/kubeovn:$(call settag,$(KUBEOVN_TAG)) \ --tag $(REGISTRY)/kubeovn:$(call settag,$(KUBEOVN_TAG)-$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/kubeovn:latest \ diff --git a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml index cf67c7d9..7444af6a 100644 --- a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml @@ -15,12 +15,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v1.13.8 +version: v1.13.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.13.8" +appVersion: "1.13.11" kubeVersion: ">= 1.23.0-0" diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml index 5c6afffa..2f5ef406 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml @@ -83,6 +83,9 @@ spec: - --node-switch={{ .Values.networking.NODE_SUBNET }} - --node-switch-cidr={{ index $cozyConfig.data "ipv4-join-cidr" }} - --service-cluster-ip-range={{ index $cozyConfig.data "ipv4-svc-cidr" }} + {{- if .Values.global.logVerbosity }} + - --v={{ .Values.global.logVerbosity }} + {{- end }} - --network-type={{- .Values.networking.NETWORK_TYPE }} - --default-provider-name={{ .Values.networking.vlan.PROVIDER_NAME }} - --default-interface-name={{- .Values.networking.vlan.VLAN_INTERFACE_NAME }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml index 3d9a7e88..3a749f84 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml @@ -35,11 +35,7 @@ spec: command: - sh - -xec - - {{ if not .Values.DISABLE_MODULES_MANAGEMENT -}} - iptables -V - {{- else -}} - echo "nothing to do" - {{- end }} + - iptables -V securityContext: allowPrivilegeEscalation: true capabilities: @@ -93,6 +89,9 @@ spec: - --node-switch={{ .Values.networking.NODE_SUBNET }} - --encap-checksum=true - --service-cluster-ip-range={{ index $cozyConfig.data "ipv4-svc-cidr" }} + {{- if .Values.global.logVerbosity }} + - --v={{ .Values.global.logVerbosity }} + {{- end }} {{- if eq .Values.networking.NETWORK_TYPE "vlan" }} - --iface= {{- else}} @@ -125,9 +124,6 @@ spec: - NET_RAW - SYS_ADMIN - SYS_PTRACE - {{- if not .Values.DISABLE_MODULES_MANAGEMENT }} - - SYS_MODULE - {{- end }} - SYS_NICE env: - name: ENABLE_SSL @@ -271,10 +267,10 @@ spec: {{- if .Values.cni_conf.MOUNT_LOCAL_BIN_DIR }} - name: local-bin hostPath: - path: {{ .Values.cni_conf.MOUNT_LOCAL_BIN_DIR }} + path: {{ .Values.cni_conf.LOCAL_BIN_DIR }} {{- end }} {{- if .Values.func.ENABLE_OVN_IPSEC }} - name: ovs-ipsec-keys hostPath: - path: /etc/origin/ovs_ipsec_keys + path: {{ .Values.OPENVSWITCH_DIR }} {{- end }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml index 33fa06d3..003d0c71 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml @@ -49,8 +49,9 @@ spec: - -xec - | chown -R nobody: /var/run/ovn /var/log/ovn /etc/openvswitch /var/run/openvswitch /var/log/openvswitch - {{- if not .Values.DISABLE_MODULES_MANAGEMENT }} iptables -V + {{- if not .Values.DISABLE_MODULES_MANAGEMENT }} + /usr/share/openvswitch/scripts/ovs-ctl load-kmod {{- else }} ln -sf /bin/true /usr/local/sbin/modprobe ln -sf /bin/true /usr/local/sbin/modinfo @@ -64,6 +65,9 @@ spec: privileged: true runAsUser: 0 volumeMounts: + - mountPath: /lib/modules + name: host-modules + readOnly: true - mountPath: /usr/local/sbin name: usr-local-sbin - mountPath: /var/log/ovn @@ -96,9 +100,7 @@ spec: add: - NET_ADMIN - NET_BIND_SERVICE - {{- if not .Values.DISABLE_MODULES_MANAGEMENT }} - - SYS_MODULE - {{- end }} + - NET_RAW - SYS_NICE - SYS_ADMIN env: diff --git a/packages/system/kubeovn/charts/kube-ovn/values.yaml b/packages/system/kubeovn/charts/kube-ovn/values.yaml index 98c6bb2c..d6185a9c 100644 --- a/packages/system/kubeovn/charts/kube-ovn/values.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/values.yaml @@ -10,7 +10,7 @@ global: repository: kube-ovn dpdkRepository: kube-ovn-dpdk vpcRepository: vpc-nat-gateway - tag: v1.13.8 + tag: v1.13.11 support_arm: true thirdparty: true diff --git a/packages/system/kubeovn/images/kubeovn/Dockerfile b/packages/system/kubeovn/images/kubeovn/Dockerfile index be05d4b8..a3e85382 100644 --- a/packages/system/kubeovn/images/kubeovn/Dockerfile +++ b/packages/system/kubeovn/images/kubeovn/Dockerfile @@ -1,54 +1,2 @@ -# syntax = docker/dockerfile:experimental -ARG VERSION=v1.13.8 -ARG BASE_TAG=$VERSION - -FROM golang:1.23-bookworm as builder - -ARG TAG=v1.13.8 -RUN git clone --branch ${TAG} --depth 1 https://github.com/kubeovn/kube-ovn /source - -WORKDIR /source - -COPY patches /patches -RUN git apply /patches/*.diff -RUN make build-go - -WORKDIR /source/dist/images - -# imported from https://github.com/kubeovn/kube-ovn/blob/master/dist/images/Dockerfile -FROM kubeovn/kube-ovn-base:$BASE_TAG AS setcap - -COPY --from=builder /source/dist/images/*.sh /kube-ovn/ -COPY --from=builder /source/dist/images/kubectl-ko /kube-ovn/kubectl-ko -COPY --from=builder /source/dist/images/01-kube-ovn.conflist /kube-ovn/01-kube-ovn.conflist - -COPY --from=builder /source/dist/images/kube-ovn /kube-ovn/kube-ovn -COPY --from=builder /source/dist/images/kube-ovn-cmd /kube-ovn/kube-ovn-cmd -COPY --from=builder /source/dist/images/kube-ovn-daemon /kube-ovn/kube-ovn-daemon -COPY --from=builder /source/dist/images/kube-ovn-controller /kube-ovn/kube-ovn-controller -RUN ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-monitor && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-speaker && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-webhook && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-leader-checker && \ - ln -s /kube-ovn/kube-ovn-cmd /kube-ovn/kube-ovn-ic-controller && \ - ln -s /kube-ovn/kube-ovn-controller /kube-ovn/kube-ovn-pinger && \ - setcap CAP_NET_BIND_SERVICE+eip /kube-ovn/kube-ovn-cmd && \ - setcap CAP_NET_RAW,CAP_NET_BIND_SERVICE+eip /kube-ovn/kube-ovn-controller && \ - setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE,CAP_SYS_ADMIN+eip /kube-ovn/kube-ovn-daemon - -FROM kubeovn/kube-ovn-base:$BASE_TAG - -COPY --chmod=0644 --from=builder /source/dist/images/logrotate/* /etc/logrotate.d/ -COPY --from=builder /source/dist/images/grace_stop_ovn_controller /usr/share/ovn/scripts/grace_stop_ovn_controller - -COPY --from=setcap /kube-ovn /kube-ovn -RUN /kube-ovn/iptables-wrapper-installer.sh --no-sanity-check - -WORKDIR /kube-ovn - -# Fix https://github.com/kubeovn/kube-ovn/issues/4526 -RUN setcap CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_SYS_ADMIN+eip /usr/lib/openvswitch-switch/ovs-vswitchd \ - && setcap CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_SYS_ADMIN+eip /usr/sbin/xtables-legacy-multi \ - && setcap CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_SYS_ADMIN+eip /usr/sbin/xtables-nft-multi \ - && setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE,CAP_SYS_ADMIN+eip /usr/sbin/ipset \ - && setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_SYS_ADMIN+eip /usr/bin/ip +ARG VERSION=v1.13.11 +FROM kubeovn/kube-ovn:${VERSION} diff --git a/packages/system/kubeovn/images/kubeovn/patches/disable-nm-syncer.diff b/packages/system/kubeovn/images/kubeovn/patches/disable-nm-syncer.diff deleted file mode 100644 index c9c683f9..00000000 --- a/packages/system/kubeovn/images/kubeovn/patches/disable-nm-syncer.diff +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/pkg/daemon/controller_linux.go b/pkg/daemon/controller_linux.go -index 07014d11..7ff19ae0 100644 ---- a/pkg/daemon/controller_linux.go -+++ b/pkg/daemon/controller_linux.go -@@ -118,9 +118,6 @@ func (c *Controller) initRuntime() error { - c.k8siptables[kubeovnv1.ProtocolIPv6] = k8siptables.New(c.k8sExec, k8siptables.ProtocolIPv6) - } - -- c.nmSyncer = newNetworkManagerSyncer() -- c.nmSyncer.Run(c.transferAddrsAndRoutes) -- - return nil - } - diff --git a/packages/system/kubeovn/patches/cozyconfig.diff b/packages/system/kubeovn/patches/cozyconfig.diff index c5a14190..f7a683f7 100644 --- a/packages/system/kubeovn/patches/cozyconfig.diff +++ b/packages/system/kubeovn/patches/cozyconfig.diff @@ -3,7 +3,7 @@ diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml b/ index d9a9a67..b2e12dd 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -@@ -51,18 +51,12 @@ spec: +@@ -51,18 +51,15 @@ spec: - bash - /kube-ovn/start-cniserver.sh args: @@ -21,6 +21,9 @@ index d9a9a67..b2e12dd 100644 - {{ .Values.ipv6.SVC_CIDR }} - {{- end }} + - --service-cluster-ip-range={{ index $cozyConfig.data "ipv4-svc-cidr" }} ++ {{- if .Values.global.logVerbosity }} ++ - --v={{ .Values.global.logVerbosity }} ++ {{- end }} {{- if eq .Values.networking.NETWORK_TYPE "vlan" }} - --iface= {{- else}} @@ -28,7 +31,7 @@ diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy index 0e69494..756eb7c 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml -@@ -52,46 +52,19 @@ spec: +@@ -52,46 +52,22 @@ spec: image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} imagePullPolicy: {{ .Values.image.pullPolicy }} args: @@ -77,6 +80,9 @@ index 0e69494..756eb7c 100644 - {{- end }} + - --node-switch-cidr={{ index $cozyConfig.data "ipv4-join-cidr" }} + - --service-cluster-ip-range={{ index $cozyConfig.data "ipv4-svc-cidr" }} ++ {{- if .Values.global.logVerbosity }} ++ - --v={{ .Values.global.logVerbosity }} ++ {{- end }} - --network-type={{- .Values.networking.NETWORK_TYPE }} - --default-provider-name={{ .Values.networking.vlan.PROVIDER_NAME }} - --default-interface-name={{- .Values.networking.vlan.VLAN_INTERFACE_NAME }} diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index f66fc737..c9283b54 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -22,4 +22,4 @@ global: images: kubeovn: repository: kubeovn - tag: v1.13.8@sha256:071a93df2dce484b347bbace75934ca9e1743668bfe6f1161ba307dee204767d + tag: v1.13.11@sha256:bbae091631c3ac6dbdd346c19187322211a9afe397566f601393a2cb338b5aeb diff --git a/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml b/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml new file mode 100644 index 00000000..58eef4fa --- /dev/null +++ b/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml @@ -0,0 +1,29 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} +{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} + + +{{- if and (has "cdi-uploadproxy" $exposeServices) }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/backend-protocol: HTTPS + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + name: cdi-uploadproxy + namespace: cozy-kubevirt-cdi +spec: + ingressClassName: {{ $exposeIngress }} + rules: + - host: cdi-uploadproxy.{{ $host }} + http: + paths: + - backend: + service: + name: cdi-uploadproxy + port: + number: 443 + path: / + pathType: Prefix +{{- end }} diff --git a/packages/system/kubevirt/templates/kubevirt-cr.yaml b/packages/system/kubevirt/templates/kubevirt-cr.yaml index 87889e42..b4ec5b70 100644 --- a/packages/system/kubevirt/templates/kubevirt-cr.yaml +++ b/packages/system/kubevirt/templates/kubevirt-cr.yaml @@ -10,6 +10,9 @@ spec: commonInstancetypesDeployment: enabled: false developerConfiguration: + {{- if .Values.cpuAllocationRatio }} + cpuAllocationRatio: {{ .Values.cpuAllocationRatio }} + {{- end }} featureGates: - HotplugVolumes - ExpandDisks diff --git a/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml b/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml new file mode 100644 index 00000000..b77743d0 --- /dev/null +++ b/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml @@ -0,0 +1,28 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $host := index $cozyConfig.data "root-host" }} +{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} +{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} + +{{- if and (has "vm-exportproxy" $exposeServices) }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/backend-protocol: HTTPS + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + name: vm-exportproxy + namespace: cozy-kubevirt +spec: + ingressClassName: {{ $exposeIngress }} + rules: + - host: vm-exportproxy.{{ $host }} + http: + paths: + - backend: + service: + name: vm-exportproxy + port: + number: 443 + path: / + pathType: ImplementationSpecific +{{- end }} diff --git a/packages/system/linstor/templates/podscrape.yaml b/packages/system/linstor/templates/podscrape.yaml index 91b2de49..9c334527 100644 --- a/packages/system/linstor/templates/podscrape.yaml +++ b/packages/system/linstor/templates/podscrape.yaml @@ -1,3 +1,4 @@ +{{- if .Capabilities.APIVersions.Has "operator.victoriametrics.com/v1beta1" }} apiVersion: operator.victoriametrics.com/v1beta1 kind: VMPodScrape metadata: @@ -42,3 +43,4 @@ spec: selector: matchLabels: app.kubernetes.io/component: linstor-controller +{{- end }} diff --git a/packages/system/metallb/Makefile b/packages/system/metallb/Makefile index d01bf396..fbc3dfa0 100644 --- a/packages/system/metallb/Makefile +++ b/packages/system/metallb/Makefile @@ -1,6 +1,7 @@ export NAME=metallb export NAMESPACE=cozy-$(NAME) +include ../../../scripts/common-envs.mk include ../../../scripts/package.mk update: @@ -9,3 +10,27 @@ update: helm repo update metallb helm pull metallb/metallb --untar --untardir charts rm -rf charts/metallb/charts/frr-k8s + +image-controller image-speaker: + $(eval TARGET := $(subst image-,,$@)) + $(eval VERSION := $(shell yq '.appVersion' charts/metallb/Chart.yaml)) + docker buildx build images/metallb \ + --provenance false \ + --builder=$(BUILDER) \ + --platform=$(PLATFORM) \ + --target $(TARGET) \ + --build-arg VERSION=$(VERSION) \ + --tag $(REGISTRY)/metallb-$(TARGET):$(VERSION) \ + --cache-from type=registry,ref=$(REGISTRY)/metallb-$(TARGET):latest \ + --cache-to type=inline \ + --metadata-file images/$(TARGET).json \ + --push=$(PUSH) \ + --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ + --load=$(LOAD) + REPOSITORY="$(REGISTRY)/metallb-$(TARGET)" \ + yq -i '.metallb.$(TARGET).image.repository = strenv(REPOSITORY)' values.yaml + TAG=$(VERSION)@$$(yq e '."containerimage.digest"' images/$(TARGET).json -o json -r) \ + yq -i '.metallb.$(TARGET).image.tag = strenv(TAG)' values.yaml + rm -f images/$(TARGET).json + +image: image-controller image-speaker diff --git a/packages/system/metallb/charts/metallb/Chart.lock b/packages/system/metallb/charts/metallb/Chart.lock index 81247366..79345580 100644 --- a/packages/system/metallb/charts/metallb/Chart.lock +++ b/packages/system/metallb/charts/metallb/Chart.lock @@ -1,9 +1,9 @@ dependencies: - name: crds repository: "" - version: 0.14.8 + version: 0.14.9 - name: frr-k8s repository: https://metallb.github.io/frr-k8s - version: 0.0.14 -digest: sha256:8dff488902a5b504a491bbd1a9ab0983a877ff214e163ed74106c73c939a9aa3 -generated: "2024-07-23T15:22:40.589621+03:00" + version: 0.0.16 +digest: sha256:20d9a53af12c82d35168e7524ae337341b2c7cb43e2169545185f750a718466e +generated: "2024-12-17T15:39:32.082324414+01:00" diff --git a/packages/system/metallb/charts/metallb/Chart.yaml b/packages/system/metallb/charts/metallb/Chart.yaml index a7f77b63..680ac9ba 100644 --- a/packages/system/metallb/charts/metallb/Chart.yaml +++ b/packages/system/metallb/charts/metallb/Chart.yaml @@ -1,14 +1,14 @@ apiVersion: v2 -appVersion: v0.14.8 +appVersion: v0.14.9 dependencies: - condition: crds.enabled name: crds repository: "" - version: 0.14.8 + version: 0.14.9 - condition: frrk8s.enabled name: frr-k8s repository: https://metallb.github.io/frr-k8s - version: 0.0.14 + version: 0.0.16 description: A network load-balancer implementation for Kubernetes using standard routing protocols home: https://metallb.universe.tf @@ -18,4 +18,4 @@ name: metallb sources: - https://github.com/metallb/metallb type: application -version: 0.14.8 +version: 0.14.9 diff --git a/packages/system/metallb/charts/metallb/README.md b/packages/system/metallb/charts/metallb/README.md index 202a9519..43f51ef7 100644 --- a/packages/system/metallb/charts/metallb/README.md +++ b/packages/system/metallb/charts/metallb/README.md @@ -17,7 +17,7 @@ Kubernetes: `>= 1.19.0-0` | Repository | Name | Version | |------------|------|---------| | | crds | 0.0.0 | -| https://metallb.github.io/frr-k8s | frr-k8s | 0.0.14 | +| https://metallb.github.io/frr-k8s | frr-k8s | 0.0.16 | ## Values @@ -79,17 +79,17 @@ Kubernetes: `>= 1.19.0-0` | prometheus.podMonitor.relabelings | list | `[]` | | | prometheus.prometheusRule.additionalLabels | object | `{}` | | | prometheus.prometheusRule.addressPoolExhausted.enabled | bool | `true` | | -| prometheus.prometheusRule.addressPoolExhausted.labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.addressPoolExhausted.labels.severity | string | `"critical"` | | | prometheus.prometheusRule.addressPoolUsage.enabled | bool | `true` | | | prometheus.prometheusRule.addressPoolUsage.thresholds[0].labels.severity | string | `"warning"` | | | prometheus.prometheusRule.addressPoolUsage.thresholds[0].percent | int | `75` | | | prometheus.prometheusRule.addressPoolUsage.thresholds[1].labels.severity | string | `"warning"` | | | prometheus.prometheusRule.addressPoolUsage.thresholds[1].percent | int | `85` | | -| prometheus.prometheusRule.addressPoolUsage.thresholds[2].labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[2].labels.severity | string | `"critical"` | | | prometheus.prometheusRule.addressPoolUsage.thresholds[2].percent | int | `95` | | | prometheus.prometheusRule.annotations | object | `{}` | | | prometheus.prometheusRule.bgpSessionDown.enabled | bool | `true` | | -| prometheus.prometheusRule.bgpSessionDown.labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.bgpSessionDown.labels.severity | string | `"critical"` | | | prometheus.prometheusRule.configNotLoaded.enabled | bool | `true` | | | prometheus.prometheusRule.configNotLoaded.labels.severity | string | `"warning"` | | | prometheus.prometheusRule.enabled | bool | `false` | | diff --git a/packages/system/metallb/charts/metallb/charts/crds/Chart.yaml b/packages/system/metallb/charts/metallb/charts/crds/Chart.yaml index 613d3182..e9fec846 100644 --- a/packages/system/metallb/charts/metallb/charts/crds/Chart.yaml +++ b/packages/system/metallb/charts/metallb/charts/crds/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: v0.14.8 +appVersion: v0.14.9 description: MetalLB CRDs home: https://metallb.universe.tf icon: https://metallb.universe.tf/images/logo/metallb-white.png @@ -7,4 +7,4 @@ name: crds sources: - https://github.com/metallb/metallb type: application -version: 0.14.8 +version: 0.14.9 diff --git a/packages/system/metallb/charts/metallb/charts/crds/templates/crds.yaml b/packages/system/metallb/charts/metallb/charts/crds/templates/crds.yaml index 61f100ed..8f241477 100644 --- a/packages/system/metallb/charts/metallb/charts/crds/templates/crds.yaml +++ b/packages/system/metallb/charts/metallb/charts/crds/templates/crds.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: bfdprofiles.metallb.io spec: group: metallb.io @@ -123,7 +123,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: bgpadvertisements.metallb.io spec: group: metallb.io @@ -329,7 +329,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: bgppeers.metallb.io spec: conversion: @@ -365,6 +365,8 @@ spec: - jsonPath: .spec.ebgpMultiHop name: Multi Hops type: string + deprecated: true + deprecationWarning: v1beta1 is deprecated, please use v1beta2 name: v1beta1 schema: openAPIV3Schema: @@ -526,15 +528,26 @@ spec: default: false description: To set if we want to disable MP BGP that will separate IPv4 and IPv6 route exchanges into distinct BGP sessions. type: boolean + dynamicASN: + description: |- + DynamicASN detects the AS number to use for the remote end of the session + without explicitly setting it via the ASN field. Limited to: + internal - if the neighbor's ASN is different than MyASN connection is denied. + external - if the neighbor's ASN is the same as MyASN the connection is denied. + ASN and DynamicASN are mutually exclusive and one of them must be specified. + enum: + - internal + - external + type: string ebgpMultiHop: description: To set if the BGPPeer is multi-hops away. Needed for FRR mode only. type: boolean enableGracefulRestart: description: |- - EnableGracefulRestart allows BGP peer to continue to forward data packets along - known routes while the routing protocol information is being restored. - This field is immutable because it requires restart of the BGP session - Supported for FRR mode only. + EnableGracefulRestart allows BGP peer to continue to forward data packets + along known routes while the routing protocol information is being + restored. This field is immutable because it requires restart of the BGP + session. Supported for FRR mode only. type: boolean x-kubernetes-validations: - message: EnableGracefulRestart cannot be changed after creation @@ -622,7 +635,9 @@ spec: type: object x-kubernetes-map-type: atomic peerASN: - description: AS number to expect from the remote end of the session. + description: |- + AS number to expect from the remote end of the session. + ASN and DynamicASN are mutually exclusive and one of them must be specified. format: int32 maximum: 4294967295 minimum: 0 @@ -649,7 +664,6 @@ spec: type: string required: - myASN - - peerASN - peerAddress type: object status: @@ -665,7 +679,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: communities.metallb.io spec: group: metallb.io @@ -730,7 +744,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: ipaddresspools.metallb.io spec: group: metallb.io @@ -940,7 +954,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: l2advertisements.metallb.io spec: group: metallb.io @@ -1120,7 +1134,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.16.3 name: servicel2statuses.metallb.io spec: group: metallb.io diff --git a/packages/system/metallb/charts/metallb/templates/controller.yaml b/packages/system/metallb/charts/metallb/templates/controller.yaml index 6129cd87..8fd9c477 100644 --- a/packages/system/metallb/charts/metallb/templates/controller.yaml +++ b/packages/system/metallb/charts/metallb/templates/controller.yaml @@ -84,7 +84,7 @@ spec: - name: METALLB_DEPLOYMENT value: {{ template "metallb.fullname" . }}-controller {{- end }} - {{- if .Values.speaker.frr.enabled }} + {{- if and .Values.speaker.enabled .Values.speaker.frr.enabled }} - name: METALLB_BGP_TYPE value: frr {{- end }} diff --git a/packages/system/metallb/charts/metallb/templates/podmonitor.yaml b/packages/system/metallb/charts/metallb/templates/podmonitor.yaml index 93a7fd69..42de8818 100644 --- a/packages/system/metallb/charts/metallb/templates/podmonitor.yaml +++ b/packages/system/metallb/charts/metallb/templates/podmonitor.yaml @@ -36,6 +36,7 @@ spec: relabelings: {{- toYaml .Values.prometheus.podMonitor.relabelings | nindent 4 }} {{- end }} +{{- if .Values.speaker.enabled }} --- apiVersion: monitoring.coreos.com/v1 kind: PodMonitor @@ -74,6 +75,7 @@ spec: relabelings: {{- toYaml .Values.prometheus.podMonitor.relabelings | nindent 4 }} {{- end }} +{{- end }} --- {{- if .Values.prometheus.rbacPrometheus }} apiVersion: rbac.authorization.k8s.io/v1 diff --git a/packages/system/metallb/charts/metallb/templates/prometheusrules.yaml b/packages/system/metallb/charts/metallb/templates/prometheusrules.yaml index e811ef13..64e44c60 100644 --- a/packages/system/metallb/charts/metallb/templates/prometheusrules.yaml +++ b/packages/system/metallb/charts/metallb/templates/prometheusrules.yaml @@ -19,8 +19,8 @@ spec: {{- if .Values.prometheus.prometheusRule.staleConfig.enabled }} - alert: MetalLBStaleConfig annotations: - message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod - }} has a stale config for > 1 minute'`}} + summary: {{`'Stale config on {{ $labels.pod }}'`}} + description: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod }} has a stale config for > 1 minute'`}} expr: metallb_k8s_client_config_stale_bool{job=~"{{ template "metallb.fullname" . }}.*"} == 1 for: 1m {{- with .Values.prometheus.prometheusRule.staleConfig.labels }} @@ -31,8 +31,8 @@ spec: {{- if .Values.prometheus.prometheusRule.configNotLoaded.enabled }} - alert: MetalLBConfigNotLoaded annotations: - message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod - }} has not loaded for > 1 minute'`}} + summary: {{`'Config on {{ $labels.pod }} has not been loaded'`}} + description: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod }} has not loaded for > 1 minute'`}} expr: metallb_k8s_client_config_loaded_bool{job=~"{{ template "metallb.fullname" . }}.*"} == 0 for: 1m {{- with .Values.prometheus.prometheusRule.configNotLoaded.labels }} @@ -43,8 +43,8 @@ spec: {{- if .Values.prometheus.prometheusRule.addressPoolExhausted.enabled }} - alert: MetalLBAddressPoolExhausted annotations: - message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod - }} has exhausted address pool {{ $labels.pool }} for > 1 minute'`}} + summary: {{`'Exhausted address pool on {{ $labels.pod }}'`}} + description: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod }} has exhausted address pool {{ $labels.pool }} for > 1 minute'`}} expr: metallb_allocator_addresses_in_use_total >= on(pool) metallb_allocator_addresses_total for: 1m {{- with .Values.prometheus.prometheusRule.addressPoolExhausted.labels }} @@ -57,8 +57,8 @@ spec: {{- range .Values.prometheus.prometheusRule.addressPoolUsage.thresholds }} - alert: MetalLBAddressPoolUsage{{ .percent }}Percent annotations: - message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod - }} has address pool {{ $labels.pool }} past `}}{{ .percent }}{{`% usage for > 1 minute'`}} + summary: {{`'Exhausted address pool on {{ $labels.pod }}'`}} + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod }} has address pool {{ $labels.pool }} past `}}{{ .percent }}{{`% usage for > 1 minute'`}} expr: ( metallb_allocator_addresses_in_use_total / on(pool) metallb_allocator_addresses_total ) * 100 > {{ .percent }} {{- with .labels }} labels: @@ -69,8 +69,8 @@ spec: {{- if .Values.prometheus.prometheusRule.bgpSessionDown.enabled }} - alert: MetalLBBGPSessionDown annotations: - message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod - }} has BGP session {{ $labels.peer }} down for > 1 minute'`}} + summary: {{`'BGP session down on {{ $labels.pod }}'`}} + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod }} has BGP session {{ $labels.peer }} down for > 1 minute'`}} expr: metallb_bgp_session_up{job=~"{{ template "metallb.fullname" . }}.*"} == 0 for: 1m {{- with .Values.prometheus.prometheusRule.bgpSessionDown.labels }} diff --git a/packages/system/metallb/charts/metallb/templates/rbac.yaml b/packages/system/metallb/charts/metallb/templates/rbac.yaml index e7fc5d97..10ffbd8a 100644 --- a/packages/system/metallb/charts/metallb/templates/rbac.yaml +++ b/packages/system/metallb/charts/metallb/templates/rbac.yaml @@ -19,11 +19,11 @@ rules: resources: ["events"] verbs: ["create", "patch"] - apiGroups: ["admissionregistration.k8s.io"] - resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + resources: ["validatingwebhookconfigurations"] resourceNames: ["metallb-webhook-configuration"] verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] - apiGroups: ["admissionregistration.k8s.io"] - resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + resources: ["validatingwebhookconfigurations"] verbs: ["list", "watch"] - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] @@ -41,6 +41,7 @@ rules: resources: ["subjectaccessreviews"] verbs: ["create"] {{- end }} +{{- if .Values.speaker.enabled }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -72,7 +73,7 @@ rules: {{- if or .Values.frrk8s.enabled .Values.frrk8s.external }} - apiGroups: ["frrk8s.metallb.io"] resources: ["frrconfigurations"] - verbs: ["get", "list", "watch","create","update"] + verbs: ["get", "list", "watch","create","update","delete"] {{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 @@ -109,6 +110,7 @@ rules: - apiGroups: ["metallb.io"] resources: ["communities"] verbs: ["get", "list", "watch"] +{{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -117,7 +119,7 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "metallb.labels" . | nindent 4 }} rules: -{{- if .Values.speaker.memberlist.enabled }} +{{- if and .Values.speaker.enabled .Values.speaker.memberlist.enabled }} - apiGroups: [""] resources: ["secrets"] verbs: ["create", "get", "list", "watch"] @@ -166,6 +168,7 @@ roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: {{ template "metallb.fullname" . }}:controller +{{- if .Values.speaker.enabled }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -195,6 +198,7 @@ roleRef: subjects: - kind: ServiceAccount name: {{ include "metallb.speaker.serviceAccountName" . }} +{{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/packages/system/metallb/charts/metallb/templates/service-accounts.yaml b/packages/system/metallb/charts/metallb/templates/service-accounts.yaml index 9615acf3..8d92a040 100644 --- a/packages/system/metallb/charts/metallb/templates/service-accounts.yaml +++ b/packages/system/metallb/charts/metallb/templates/service-accounts.yaml @@ -13,7 +13,7 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} {{- end }} -{{- if .Values.speaker.serviceAccount.create }} +{{- if and .Values.speaker.enabled .Values.speaker.serviceAccount.create }} --- apiVersion: v1 kind: ServiceAccount diff --git a/packages/system/metallb/charts/metallb/templates/servicemonitor.yaml b/packages/system/metallb/charts/metallb/templates/servicemonitor.yaml index 8be88dd3..2a92e48a 100644 --- a/packages/system/metallb/charts/metallb/templates/servicemonitor.yaml +++ b/packages/system/metallb/charts/metallb/templates/servicemonitor.yaml @@ -1,4 +1,9 @@ +{{- if and .Values.prometheus.serviceMonitor.enabled .Values.prometheus.podMonitor.enabled }} +{{- fail "prometheus.serviceMonitor.enabled and prometheus.podMonitor.enabled cannot both be set" }} +{{- end }} + {{- if .Values.prometheus.serviceMonitor.enabled }} +{{- if .Values.speaker.enabled }} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: @@ -89,6 +94,7 @@ spec: {{- end }} sessionAffinity: None type: ClusterIP +{{- end }} --- apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor @@ -97,7 +103,6 @@ metadata: namespace: {{ .Release.Namespace | quote }} labels: {{- include "metallb.labels" . | nindent 4 }} - app.kubernetes.io/component: speaker {{- if .Values.prometheus.serviceMonitor.controller.additionalLabels }} {{ toYaml .Values.prometheus.serviceMonitor.controller.additionalLabels | indent 4 }} {{- end }} diff --git a/packages/system/metallb/charts/metallb/values.yaml b/packages/system/metallb/charts/metallb/values.yaml index bc96d355..50d26bca 100644 --- a/packages/system/metallb/charts/metallb/values.yaml +++ b/packages/system/metallb/charts/metallb/values.yaml @@ -42,7 +42,7 @@ prometheus: # certificate to be used. controllerMetricsTLSSecret: "" - # prometheus doens't have the permission to scrape all namespaces so we give it permission to scrape metallb's one + # prometheus doesn't have the permission to scrape all namespaces so we give it permission to scrape metallb's one rbacPrometheus: true # the service account used by prometheus @@ -64,7 +64,7 @@ prometheus: # enable support for Prometheus Operator enabled: false - # optional additionnal labels for podMonitors + # optional additional labels for podMonitors additionalLabels: {} # optional annotations for podMonitors @@ -143,7 +143,7 @@ prometheus: # enable alertmanager alerts enabled: false - # optional additionnal labels for prometheusRules + # optional additional labels for prometheusRules additionalLabels: {} # optional annotations for prometheusRules @@ -165,7 +165,7 @@ prometheus: addressPoolExhausted: enabled: true labels: - severity: alert + severity: critical addressPoolUsage: enabled: true @@ -178,13 +178,13 @@ prometheus: severity: warning - percent: 95 labels: - severity: alert + severity: critical # MetalLBBGPSessionDown bgpSessionDown: enabled: true labels: - severity: alert + severity: critical extraAlerts: [] diff --git a/packages/system/metallb/images/metallb/Dockerfile b/packages/system/metallb/images/metallb/Dockerfile new file mode 100644 index 00000000..477c3fc0 --- /dev/null +++ b/packages/system/metallb/images/metallb/Dockerfile @@ -0,0 +1,87 @@ +# syntax=docker/dockerfile:1.2 + +FROM --platform=$BUILDPLATFORM docker.io/golang:1.22.7 AS builder + +ARG VERSION +ARG GIT_COMMIT=dev +ARG GIT_BRANCH=dev +ARG TARGETARCH +ARG TARGETOS +ARG TARGETPLATFORM + +WORKDIR /go/go.universe.tf/metallb + +RUN --mount=type=cache,target=/go/pkg/mod \ + curl -sSL https://github.com/metallb/metallb/archive/refs/tags/${VERSION}.tar.gz \ + | tar -xzvf- --strip=1 + +RUN curl -sSLO https://github.com/metallb/metallb/pull/2726.diff && \ + git apply 2726.diff + +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go mod download -x + +RUN case ${TARGETPLATFORM} in \ + "linux/arm/v6") export VARIANT="6" ;; \ + "linux/arm/v7") export VARIANT="7" ;; \ + *) export VARIANT="" ;; \ + esac && \ + CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH GOARM=$VARIANT \ + go build -v -o /build/controller \ + -ldflags "-X 'go.universe.tf/metallb/internal/version.gitCommit=${GIT_COMMIT}' \ + -X 'go.universe.tf/metallb/internal/version.gitBranch=${GIT_BRANCH}'" \ + ./controller \ + && \ + CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH GOARM=$VARIANT \ + go build -v -o /build/frr-metrics \ + -ldflags "-X 'go.universe.tf/metallb/internal/version.gitCommit=${GIT_COMMIT}' \ + -X 'go.universe.tf/metallb/internal/version.gitBranch=${GIT_BRANCH}'" \ + frr-tools/metrics/exporter.go \ + && \ + CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH GOARM=$VARIANT \ + go build -v -o /build/cp-tool \ + -ldflags "-X 'go.universe.tf/metallb/internal/version.gitCommit=${GIT_COMMIT}' \ + -X 'go.universe.tf/metallb/internal/version.gitBranch=${GIT_BRANCH}'" \ + frr-tools/cp-tool/cp-tool.go \ + && \ + CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH GOARM=$VARIANT \ + go build -v -o /build/speaker \ + -ldflags "-X 'go.universe.tf/metallb/internal/version.gitCommit=${GIT_COMMIT}' \ + -X 'go.universe.tf/metallb/internal/version.gitBranch=${GIT_BRANCH}'" \ + ./speaker + +FROM gcr.io/distroless/static:latest as controller + +COPY --from=builder /build/controller /controller + +LABEL org.opencontainers.image.authors="metallb" \ + org.opencontainers.image.url="https://github.com/metallb/metallb" \ + org.opencontainers.image.documentation="https://metallb.universe.tf" \ + org.opencontainers.image.source="https://github.com/cozystack/cozystack" \ + org.opencontainers.image.vendor="metallb" \ + org.opencontainers.image.licenses="Apache-2.0" \ + org.opencontainers.image.description="Metallb Controller" \ + org.opencontainers.image.title="controller" \ + org.opencontainers.image.base.name="gcr.io/distroless/static:latest" + +ENTRYPOINT ["/controller"] + +FROM gcr.io/distroless/static:latest as speaker + +COPY --from=builder /build/cp-tool /cp-tool +COPY --from=builder /build/speaker /speaker +COPY --from=builder /build/frr-metrics /frr-metrics +COPY --from=builder /go/go.universe.tf/metallb/frr-tools/reloader/frr-reloader.sh /frr-reloader.sh + +LABEL org.opencontainers.image.authors="metallb" \ + org.opencontainers.image.url="https://github.com/metallb/metallb" \ + org.opencontainers.image.documentation="https://metallb.universe.tf" \ + org.opencontainers.image.source="https://github.com/cozystack/cozystack" \ + org.opencontainers.image.vendor="metallb" \ + org.opencontainers.image.licenses="Apache-2.0" \ + org.opencontainers.image.description="Metallb speaker" \ + org.opencontainers.image.title="speaker" \ + org.opencontainers.image.base.name="gcr.io/distroless/static:latest" + +ENTRYPOINT ["/speaker"] diff --git a/packages/system/metallb/values.yaml b/packages/system/metallb/values.yaml index 737f17cf..3fb0a10f 100644 --- a/packages/system/metallb/values.yaml +++ b/packages/system/metallb/values.yaml @@ -1,6 +1,11 @@ metallb: crds: enabled: true - - #speaker: - # tolerateMaster: false + controller: + image: + repository: ghcr.io/cozystack/cozystack/metallb-controller + tag: v0.14.9@sha256:73c3156d913a2ff15a26ca42fcbeee6fa115602bcdb78870dcfab9359acd9cb3 + speaker: + image: + repository: ghcr.io/cozystack/cozystack/metallb-speaker + tag: v0.14.9@sha256:9af9f0a6922784f066653f2c0d940d5f2de7ffea132d2df488457b61465b7716 diff --git a/packages/system/piraeus-operator/templates/alerts.yaml b/packages/system/piraeus-operator/templates/alerts.yaml index 70d47014..c8387a65 100644 --- a/packages/system/piraeus-operator/templates/alerts.yaml +++ b/packages/system/piraeus-operator/templates/alerts.yaml @@ -1,7 +1,8 @@ {{- $files := .Files.Glob "alerts/*.yaml" -}} +{{- if .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" }} {{- range $path, $file := $files }} --- # from: {{ $path }} {{ toString $file }} - +{{- end }} {{- end -}} diff --git a/scripts/common-envs.mk b/scripts/common-envs.mk index ee0e9fac..98f4652a 100644 --- a/scripts/common-envs.mk +++ b/scripts/common-envs.mk @@ -1,7 +1,7 @@ REGISTRY := ghcr.io/cozystack/cozystack PUSH := 1 LOAD := 0 -VERSION = $(patsubst v%,%,$(shell git describe --tags --abbrev=0)) +COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags)) TAG = $(shell git describe --tags --exact-match 2>/dev/null || echo latest) # Returns 'latest' if the git tag is not assigned, otherwise returns the provided value @@ -9,8 +9,14 @@ define settag $(if $(filter $(TAG),latest),latest,$(1)) endef -ifeq ($(VERSION),) +ifeq ($(COZYSTACK_VERSION),) $(shell git remote add upstream https://github.com/cozystack/cozystack.git || true) $(shell git fetch upstream --tags) - VERSION = $(patsubst v%,%,$(shell git describe --tags --abbrev=0)) -endif \ No newline at end of file + COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags)) +endif + +# Get the name of the selected docker buildx builder +BUILDER ?= $(shell docker buildx inspect --bootstrap | head -n2 | awk '/^Name:/{print $$NF}') +# Get platforms supported by the builder +PLATFORM ?= $(shell docker buildx ls --format=json | jq -r 'select(.Name == "$(BUILDER)") | [.Nodes[].Platforms // []] | flatten | unique | map(select(test("^linux/amd64$$|^linux/arm64$$"))) | join(",")') + diff --git a/scripts/migrations/11 b/scripts/migrations/11 old mode 100644 new mode 100755 diff --git a/scripts/migrations/12 b/scripts/migrations/12 new file mode 100755 index 00000000..fcb951bc --- /dev/null +++ b/scripts/migrations/12 @@ -0,0 +1,35 @@ +#!/bin/sh +# Migration 12 --> 13 + +# Copy configuration from ingress to cozystack configmap +if kubectl get hr -n tenant-root tenant-root > /dev/null; then + expose_services=$( + kubectl get hr -n tenant-root ingress -o go-template='{{ with .spec }}{{ with .values }}{{ if .dashboard }}dashboard,{{ end }}{{ if .cdiUploadProxy }}cdi-uploadproxy,{{ end }}{{ if .virtExportProxy }}vm-exportproxy,{{ end }}{{ end }}{{ end }}' + ) + expose_services=$(echo "$expose_services" | awk '{sub(/,$/,""); print}') + + expose_external_ips=$( + kubectl get hr -n tenant-root ingress -o go-template='{{ with .spec }}{{ with .values }}{{ if .externalIPs }}{{ range .externalIPs }}{{ . }},{{ end }}{{ end }}{{ end }}{{ end }}' + ) + expose_external_ips=$(echo "$expose_external_ips" | awk '{sub(/,$/,""); print}') + + existing_expose_external_ips=$(kubectl get cm -n cozy-system cozystack -o go-template='{{ index .data "expose-external-ips" }}') + existing_expose_services=$(kubectl get cm -n cozy-system cozystack -o go-template='{{ index .data "expose-services" }}') + + if [ "$existing_expose_external_ips" == "<no value>" ]; then + kubectl patch cm -n cozy-system cozystack --type merge -p="{\"data\":{\"expose-external-ips\":\"$expose_external_ips\"}}" + fi + + if [ "$existing_expose_services" == "<no value>" ]; then + kubectl patch cm -n cozy-system cozystack --type merge -p="{\"data\":{\"expose-services\":\"$expose_services\"}}" + fi + + kubectl patch hr -n tenant-root ingress --type json -p='[{"op": "remove", "path": "/spec/values/dashboard"}]' || true + kubectl patch hr -n tenant-root ingress --type json -p='[{"op": "remove", "path": "/spec/values/cdiUploadProxy"}]' || true + kubectl patch hr -n tenant-root ingress --type json -p='[{"op": "remove", "path": "/spec/values/virtExportProxy"}]' || true + kubectl patch hr -n tenant-root ingress --type json -p='[{"op": "remove", "path": "/spec/values/externalIPs"}]' || true + kubectl patch hr -n tenant-root ingress --type merge -p='{"spec":{"chart":{"spec":{"version":"1.6.0"}}}}' +fi + +# Write version to cozystack-version config +kubectl create configmap -n cozy-system cozystack-version --from-literal=version=13 --dry-run=client -o yaml | kubectl apply -f- diff --git a/scripts/package.mk b/scripts/package.mk index ca537213..62702321 100644 --- a/scripts/package.mk +++ b/scripts/package.mk @@ -29,3 +29,11 @@ delete: check suspend ## Delete Helm release from a Kubernetes cluster check: @if [ -z "$(NAME)" ]; then echo "env NAME is not set!" >&2; exit 1; fi @if [ -z "$(NAMESPACE)" ]; then echo "env NAMESPACE is not set!" >&2; exit 1; fi + +clean: + rm -rf charts/ + +%-update: + helm repo add $(REPO_NAME) $(REPO_URL) + helm repo update $(REPO_NAME) + helm pull $(REPO_NAME)/$(CHART_NAME) --untar --untardir charts --version "$(CHART_VERSION)"